Django模板層的知識包括標籤、過濾器、自定義標籤、自定義過濾器以及inclusion_tag,最重要的是模板的繼承和導入。css
首先模板層最重要的是模板語法,以前咱們提過涉及到變量用模板語法{{ }},涉及到邏輯用模板語法{% %},這裏再追加幾點。過濾器在模板語法{{ }}中寫,並且只能傳兩個參數;標籤在模板語法{%%}中寫,並且能傳多個參數(參數間用空格隔開)。模板的繼承與導入也是在模板語法{%%}中寫。html
接下來再回顧一下後端朝前端頁面傳遞數據的兩種方式:前端
# 第一種 return render(request, 'index.html', {'nums': nums}) # 第二種 return render(request, 'index.html', locals())
該兩種方法有利有弊,不過咱們偏心locals()。python
後端除了能向前端提交python的基本數據類型:int、float、str、list、dict、tuple、set數據外,還能提交函數與類的對象。當咱們傳遞函數名給前端時,會自動調用該函數拿到函數return的結果,可是不支持傳參,因此只能傳遞無參函數名。當傳遞類的對象obj給前端時,至關於print(obj),前端拿到的是該obj的內存地址,由於print(obj)走的是類的__str__()方法。因此傳遞類的對象時,咱們能夠重寫__str__()讓前端拿到想要的內容。jquery
前端想要獲取後端傳遞過來的容器類型中的元素時,統一使用句點符(.):django
<!--假設前端拿到的數據是 L = [1, 2, 3] D = {'age': 18}--> {{ L }} <!--[1, 2, 3]--> {{ L.1 }} <!-- 2 索引也是從0開始--> {{ D }} <!--{'age': 18}--> {{ L.age }} <!-- 18 -->
前端能夠調用python自帶的內置方法,不過只能調用不須要傳參的,好比字典dic的dic.keys(),dic.values(),dic.items()等,注意:在前端調用方法不須要加(),直接dic.keys便可。bootstrap
模板語法的註釋不會展現到前端(用谷歌瀏覽器的檢查也看不到),只能在後端看到,原生的HTML註釋先後端均可以看到。後端
過濾器在模板語法{{ }}中書寫,實際上過濾器內部走的是後端的語法,過濾器最多支持傳兩個參數(會把|左邊的參數當作過濾器的第一個參數傳進去),不過能夠把參數改爲容器類型,而後在內部動手腳處理參數中的數據,間接實現傳遞多參數,這須要咱們自定義過濾器來實現。瀏覽器
過濾器基本語法:{{ 參數1|過濾器名字:參數2 }} 有些過濾器沒有參數2。安全
若是file_size是204800,執行該過濾器後是 200.0KB
不須要同後端同樣加%('%Y-%m-%d'),若是ctime是2019-06-11 16:56:38.903314,執行完該過濾器後是2019-06-11。
若是s='hello world',執行完該過濾器後是‘hlow’,slice後面的參數同python字符串切片參數同樣,開頭:結尾:步長,其中步長默認爲1,切片顧頭不顧尾。
若是s='hello world',執行完該過濾器後是‘hello w...’,超出長度的部分會用...代替,當咱們參數爲10時,實際上截取的字符串長度爲7,由於...佔3位。
若是s='he llo wor ld',執行完該過濾器後是:‘he llo ...’,截取至前兩個空格,以後的內容用...表示。
若是n1=2, n2=4,那麼結果爲6。若是n1='hello', n2='world',那麼結果爲'helloworld'。
重點:
當咱們後端向前端提交的字符串含有標籤時,好比'<h1>this is title</h1>',爲了防止腳本攻擊(好比<script>while(1){alert('come on')}</script>),前端以後把你當成普通的字符串。當咱們想要讓前端幫咱們執行提交的字符串中的標籤內容時,有兩種方式。
from django.utils.safestring import mark_safe def index(request): html = reverse('index') s = '<h1>this is title</h1>' s = mark_safe(s) return render(request, 'index.html', locals()) # 前端直接{{ s }}便可
標籤在模板語法{%%}中書寫,{%%}涉及到邏輯,標籤通常是for循環,if判斷以及它們的嵌套使用,除此以外還有empty標籤。
for循環中可使用forloop來給咱們提供一些信息:
<!--l = [1, 2, 3, 4, 5]--> {% for foo in l %} <p>{{ foo }}</p> <p>{{ forloop }}</p> {% endfor %}
{% if flag %} <p>flag不爲空</p> {% else %} <p>flag是空</p> {% endif %}
{% for foo in s %} {% if forloop.first %} <p>這是第一次</p> {% elif forloop.last %} <p>這是最後一次</p> {% else %} <p>keep up</p> {% endif %} {% endfor %}
{% for foo in l %} {% if forloop.first %} <p>這是個人第一次</p> {% elif forloop.last %} <p>這是最後一次了啊</p> {% else %} <p>嗨起來!!!</p> {% endif %} {% empty %} <p>你給個人容器類型是個空啊,無法for循環</p> {% endfor %}
當後端傳來的數據中,咱們想要的數據須要句點符點不少次才能拿到且後面還須要用到該數據時,咱們能夠選擇給該數據取別名。
要自定義過濾器與標籤,必須先作三件事:
from django import template register = template.Library()
再次強調,必定要按照以上步驟進行,文件夾必定要叫templatetags!!!
from django import template register = template.Library() # 自定義過濾器 @register.filter(name='my_add') # name是HTML頁面中調用該過濾器用的名字 def my_add(a, b): return a+b
from django import template register = template.Library() @register.simple_tag(name='my_tag') def my_tag(a, b, c): return a + b + c
from django import template register = template.Library() @register.inclusion_tag('login.html', name='login') def login(n): l = ['第%s項' % i for i in range(n)] return {'l': l}
<!--login.html--> <ur> {% for foo in l %} <li>{{ foo }}</li> {% endfor %} </ur>
在該例子中,咱們在前端調用inclusion_tag時:
{% load my_tags %}
{% login 5 %}
首先會將參數5傳給login函數,函數執行完後的結果提交至login.html,而後將login.html的頁面顯示在調用該inclusion_tag的地方。
inclusion_tag會將渲染過的login.html界面返回至調用它的位置,正是由於這種機制,因此它所渲染那個html頁面中能夠不須要head和body等各類標籤,你須要返回什麼就在裏面寫什麼。
想要使用自定義的過濾器、標籤和inclusion_tag,必需要先在html界面中加載該模塊
<!--加載my_tags.py模塊--> {% load my_tags %} {{ n1|my_add:n2 }} <!--調用自定義過濾器--> {% my_tag n1 n2 n3 %} <!--調用自定義標籤--> {% login 5 %} <!--調用自定義inclusion_tag-->
1.1 首先須要被繼承的模板中劃分多個區域:
{% block 給區域起的名字 %}
{% endblock %}
1.2 一般狀況下一個模板中至少有三塊區域:
{% block css %}
頁面css代碼塊
{% endblock %}
{% block js %}
頁面js代碼塊
{% endblock %}
{% block content %}
頁面主體內容
{% endblock %}
1.3 子模板繼承模板,首先要先繼承模板全部的內容:
{% extends 'home.html' %}
1.4 根據被block快的名字修改指定區域的內容
{% block content %} <h1>登陸頁面</h1> <form action=""> <p>username:<input type="text" class="form-control"></p> <p>password:<input type="text" class="form-control"></p> <input type="submit" class="btn btn-success"> </form> {% endblock %}
1.5 可使用{{ block.super }}使用父模板的該block的內容(使用該方法是沒有提示,要手打)
{% block content %}
{{ block.super }}
{% endblock %}
注意:原模板中的block區域越多越好,由於越多表明能夠修改的細節不少,擴展性就越強。繼承後,子模板只能修改block區域中的內容。
模板導入同自定義標籤inclusion_tag有點像,都是將一個HTML頁面顯示到調用它們的地方,並且他們的HTML頁面都是要啥就寫啥就好了,不須要body、head等標籤。不過inclusion_tag是動態的,能夠傳遞參數,而模板導入是靜態的。
模塊導入{% include '想導入的html文件名' %}:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>login2</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <!--導入模板index2.html--> {% include 'index2.html' %} </body> </html>
<h1>我是這條gai最靚的仔</h1> <form action=""> <p><input type="text"></p> <p><input type="text"></p> <input type="submit"> </form>
當咱們爲了讓路由名字改變時咱們不須要修改HTML頁面和視圖函數中的內容,咱們引入了反向解析。同理,爲了防止settins.py文件夾中static文件夾的接口前綴改變而咱們不須要html頁面中head中script和link的接口前綴(須要修改的前提是他們導入的是static文件夾中的東西),咱們引入了靜態文件配置。
{% load static %} <link rel='stylesheet' href="{% static 'css/mycss.css'%}"> # 第一種方式 <link rel='stylesheet' href="{% get_static_prefix %}css/mycss.css"> # 第二種方式