django 模版 語法與使用
- 2019 年 10 月 8 日
- 筆記
目錄
django 模版語法與使用
django模板語言介紹 (摘自官方文檔) 鏈接
""" Django模板語言 Django的模板語言旨在在功能和易用性之間取得平衡。它讓那些習慣使用HTML的人感到舒服。 如果您對其他基於文本的模板語言(如Smarty 或Jinja2)有過接觸,那麼您應該對Django的模板感到賓至如歸。 哲學 如果您有編程背景,或者習慣於將編程程式碼直接混合到HTML中的語言,那麼您需要記住, Django模板系統不僅僅是嵌入到HTML中的Python。這是一種設計,模板系統用於表達,而不是程式邏輯。 Django模板系統提供的標籤功能類似於一些編程結構 如 if,布爾,for標籤,循環標籤等 - 但這些標籤不是簡單地作為相應的Python程式碼執行, 模板系統不會執行任意Python表達式。默認情況下,僅支援下面列出的標記,過濾器和語法(您可以根據需要將自己的擴展添加到模板語言中)。 哲學 為什麼使用基於文本的模板而不是基於XML的模板(如Zope的TAL)?我們希望Django的模板語言不僅可用於XML / HTML模板。 在World Online,我們將其用於電子郵件,JavaScript和CSV。您可以將模板語言用於任何基於文本的格式。 哦,還有一件事:讓人類編輯XML是虐待狂! """
什麼是模板?
模板只是一個文本文件。它可以生成任何基於文本的格式(HTML,XML,CSV等)。 模板包含變數,這些變數在評估模板時將替換為值,而變數則包含控制模板邏輯的標記。 只要是在html裡面有模板語法就不是html文件了,這樣的文件就叫做模板。
模板語句的 注釋
模板語句的注釋 {#{{ '10'|add_str:'5 '}}#} {#注釋內容#} 變數 {{ 變數 }}
- 變數:語法為 {{ }}:括弧里加要渲染變數的變數值,變數名由字母數字和下劃線組成。
- 程式碼
#views 文件函數 def template_test(request): name = '鋼蛋' age = 18 hobby = ['唱', '跳', 'rap', '籃球'] lis = [] st = '' dic = { 'name': '鐵蛋', 'age': 16, 'hobby': hobby, 'keys': 'xxxxx' } dic_2 = {} return render(request,'template_test.html', {'name':name_p,'age':age,'hobby':hobby,'lis':lis,'st':st,'dic':dic,'dic_2':dic_2}) # 模板文件html頁面 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>郭楷豐</title> </head> <body> {{ 啦啦啦啦啦 }} <p> {{ name }} </p> <p> {{ age }} </p> <p> {{ hobby }} </p> <p> {{ lis }} </p> <p> {{ st }} </p> <p> {{ dic }} </p> <p> {{ dic_2 }} </p> </body> </html>- 瀏覽器結果:

- 小結: {{ }}里填要渲染的變數,規範寫法,兩邊用括弧隔開 如 {{ 變數 }}, 後端沒有傳參的頁面不顯示


點(.)在模板語言中有特殊的含義,用來獲取對象的相應屬性值。
- 例子 程式碼 .索引 .key .屬性 .方法
#views 文件函數 def template_test(request): lis = [1, 2, 3,4,5] dic = {"name": "黑蛋"} class Person(object): def __init__(self, name, age): self.name = name self.age = age def dream(self): return " 我 is {} age {}歲...".format(self.name,self.age) gangdan = Person(name="鋼蛋", age=18) goudan = Person(name="狗蛋", age=17) tiedan = Person(name="鐵蛋", age=16) person_list = [gangdan, goudan, tiedan] return render(request, "template_test.html", {"lis": lis, "dic": dic, "person_list": person_list}) # 模板文件html頁面 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>郭楷豐</title> </head> <boby> <p>{{ lis.0 }}</p> <!--取l中的第一個參數--> <p>{{ dic.name }}</p><!--取字典中key的值--> <p>{{ person_list.0.name }}</p><!--取對象的name屬性--> <p>{{ person_list.0.dream }}</p><!--.操作只能調用不帶參數的方法--> </boby> </html>- 小結:
#註:當模板系統遇到一個(.)時,會按照如下的順序去查詢: 1. 在字典中查詢 2. 屬性或者方法 3. 數字索引 # 索引不能為負數


Tags 標籤 {% %} 表示邏輯相關的操作
- 程式碼例子
{% for foo in lis %} <!--for循環--> {% if %} <!--if判斷--> {% elif %} <!--elif判斷--> {% endif %} <!--if閉合符--> {% else %} <!--else判斷不成立執行--> {% endfor %} <!--for循環閉合符--> <!--應用 模板html程式碼--> <form action="" method="post"> <label for="inputEmail3" class="col-sm-2 control-label">書名: </label> <div class="col-sm-8"> <input type="text" name="book_name" class="form-control" value="{{ edit_obj.title }}"> <select name="pub_id" id="" class="btn btn-default btn-sm"> {% for foo in publishers %} {% if foo == edit_obj.pub %} <option selected value="{{ foo.pk }}"> {{ foo.name }}</option> {% else %} <option value="{{ foo.pk }}"> {{ foo.name }}</option> {% endif %} {% endfor %} </select> </div> <div class="text-center text-danger">{{ error }}</div> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">提交</button> </div> </form> <!--應用 python邏輯程式碼 #views 文件函數--> def edit_book(request): error = '' pk = request.GET.get('pk') edit_obj = models.Book.objects.filter(id=pk) if not edit_obj: return HttpResponse('要編輯的數據不存在') if request.method == 'POST': book_name = request.POST.get('book_name') if not book_name.strip(): error = "書名不能為空" pub_id = request.POST.get('pub_id') if edit_obj[0].title == book_name and edit_obj[0].pub_id == int(pub_id): error = "未作修改" if not error: obj = edit_obj[0] obj.title = book_name obj.pub_id = int(pub_id) obj.save() return redirect('/book_list/') publishers = models.Publisher.objects.all() return render(request,'edit_book.html',{'edit_obj':edit_obj[0],'publishers':publishers,'error':error})- 執行效果


- if語句支援 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷。
- js,python,模板語言的判斷邏輯 #python 10>5>1 =》 10>5 and 5>1 true #js 10>5>1 =》 10>5 =》 true =》 1>1 false #模板中 不支援連續連續判斷,也不支援算數運算(過濾器)
- 注意事項
- Django的模板語言不支援連續判斷,也不支援以下寫法:
{% if a > b > c %} ... {% endif %} #不支援算數運算 + - * /- Django的模板語言中屬性的優先順序大於方法
def xx(request): d = {"a": 1, "b": 2, "c": 3, "items": "100"} return render(request, "xx.html", {"data": d})- 如上,我們在使用render方法渲染一個頁面的時候,傳的字典d有一個key是items並且還有默認的 d.items() 方法,此時在模板語言中:
{{ data.items }} 默認會取d的items key的值。for循環可用的一些參數:
Variable | Description |
|---|---|
forloop.counter | 當前循環的索引值(從1開始) |
forloop.counter0 | 當前循環的索引值(從0開始) |
forloop.revcounter | 當前循環的倒序索引值(到1結束) |
forloop.revcounter0 | 當前循環的倒序索引值(到0結束) |
forloop.first | 當前循環是不是第一次循環(布爾值) |
forloop.last | 當前循環是不是最後一次循環(布爾值) |
forloop.parentloop | 本層循環的外層循環 |
- for ... empty
#for 標籤帶有一個可選的{% empty %} 從句,以便在給出的組是空的或者沒有被找到時,可以有所操作。 {% for person in person_list %} <p>{{ person.name }}</p> {% empty %} <p>sorry,no person here</p> {% endfor %}Filters 過濾器
- 用來修改變數的顯示結果, 語法: {{ value|filter_name:參數 }} ':' 左右沒有空格沒有空格沒有空格
- 設置除法除盡 divisibleby:參數

with 的使用
- 定義一個中間變數(起個別名,只在with內部生效)
#寫法一 {% with total=business.employees.count %} {{ total }} employee{{ total|pluralize }} {% endwith %} #寫法二 {% with business.employees.count as total %} {{ total }} employee{{ total|pluralize }} {% endwith %}
default 系統默認值
{{ value|default:"nothing"}} 如果value值沒傳的話就顯示nothing 註:TEMPLATES的OPTIONS可以增加一個選項:string_if_invalid:'找不到',可以替代default的的作用。 (在配置文件settings.py設置)- 配置設置變數不傳參顯示值

- 頁面效果

filesizeformat 文件大小人性化顯示
- 將值格式化為一個 「人類可讀的」 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)例如:
{{ value|filesizeformat }} 如果 value 是 123456789,輸出將會是 117.7 MBadd "加"
- 給變數加參數,字元串默認嘗試轉int類型,轉不了就拼接
{{ value|add:"2" }} value是數字4,則輸出結果為6 {{ value|add:"hello" }} value是數字666,則輸出結果為666hello {{ first|add:second }} 如果first是 [1,.2,3] ,second是 [4,5,6] ,那輸出結果是 [1,2,3,4,5,6] lower 小寫
{{ value|lower }}upper 大寫
{{ value|upper}}title 標題
{{ value|title }}ljust 左對齊
"{{ value|ljust:"10" }}"rjust 右對齊
"{{ value|rjust:"10" }}"center 居中
"{{ value|center:"15" }}"length 長度
{{ value|length }} 返回value的長度,如 value=['a', 'b', 'c', 'd']的話,就顯示4.slice 切片
{{value|slice:"2:-1"}}first 取第一個元素
{{ value|first }}last 取最後一個元素
{{ value|last }}join 使用字元串拼接列表
- 同python的str.join(list)
{{ value|join:" // " }}cut 移除value中所有的與給出的變數相同的字元串
- 如果value為'i love you',那麼將輸出'iloveyou'.
{{ value|cut:' ' }}truncatechars 按照字元截斷 ...也計數
- 如果字元串字元多於指定的字元數量,那麼會被截斷。截斷的字元串將以可翻譯的省略號序列(「...」)結尾
#參數:截斷的字元數 {{ value|truncatechars:9}} truncatewords 按照單詞進行截斷, 只針對英文(...)不計數,中文按字計算date 日期格式化
#後端 import datetime def mul(request): value = datetime.datetime.now() return render(request, 'mul.html',{'value':value}) #模板語句 {{ value|date:"Y-m-d H:i:s"}} #顯示格式 年-月-日 時:分:秒 #後端 import datetime def mul(request): now = datetime.datetime.now() return render(request, 'mul.html',{'now':now}) #模板直接使用變數 {{ now }} #顯示格式 June 19,2019,22:00 p.m. #時間格式和默認值一起使用 {{ obj.next_date|date:"Y-m-d"|default:"暫無" }}- 頁面效果



- 可格式化輸出的字元: 點擊查看
- 改配置文件設置顯示樣式 (一勞永逸的解決辦法)
#settings.py文件設置 USE_L10N = False #更換為False DATETIME_FORMAT = 'Y-m-d H:i:s' #添加 #也可以日期與時間分開設置 根據自己的需求設置 DATE_FORMAT = 'Y-m-d' TIME_FORMAT = 'H:i:s'

safe 防止xss攻擊 作用 取消轉義
- 簡單了解xss攻擊
XSS攻擊全稱跨站腳本攻擊,是為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆, 故將跨站腳本攻擊縮寫為XSS,XSS是一種在web應用中的電腦安全漏洞,它允許惡意web用戶將程式碼植入到提供給其它用戶使用的頁面中。 XSS是一種經常出現在web應用中的電腦安全漏洞,它允許惡意web用戶將程式碼植入到提供給其它用戶使用的頁面中。 比如這些程式碼包括HTML程式碼和客戶端腳本。攻擊者利用XSS漏洞旁路掉訪問控制——例如同源策略(same origin policy)。 這種類型的漏洞由於被駭客用來編寫危害性更大的網路釣魚(Phishing)攻擊而變得廣為人知。對於跨站腳本攻擊, 駭客界共識是:跨站腳本攻擊是新型的「緩衝區溢出攻擊「,而JavaScript是新型的「ShellCode」。
- xss攻擊流程

safe 主要作用
#Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,原因顯而易見,這樣是為了安全。 但是有的時候我們可能不希望這些HTML元素被轉義,比如我們做一個內容管理系統,後台添加的文章中是經過修飾的, 這些修飾可能是通過一個類似於FCKeditor編輯加註了HTML修飾符的文本,如果自動轉義的話顯示的就是保護HTML標籤的源文件。 為了在Django中關閉HTML的自動轉義有兩種方式,如果是一個單獨的變數我們可以通過過濾器「|safe」的方式告訴Django這段程式碼是安全的不必轉義。
- 正常情況下
#頁面程式碼: {% load my_tags %} {{ 'https://www.baidu.com/'|show:'百度' }} #自定過濾器程式碼 @register.filter def show(url,name): return "<a href = '{}'>{}</a>".format(url,name)- 頁面顯示效果

- 過濾器函數 加is_safe = True 解除轉義
#自定過濾器程式碼 @register.filter(is_safe = True) def show(url,name): return "<a href = '{}'>{}</a>".format(url,name)- 頁面效果

- 模板語句中加 safe 解除轉義
#模板語句 {% load my_tags %} {{ 'https://www.baidu.com/'|show:'百度'|safe }}- 頁面效果

- 也可以導入模組實現這種效果


自定義 filter
- 當普通的內置過濾器,實現不了我們的開發需求,那我們可以自定義過濾器來實現功能
自定義過濾器是只能帶有一個或兩個參數的Python函數: 變數(輸入)的值 - -不一定是一個字元串 參數的值 - 這可以有一個默認值,或完全省略 例如,在過濾器{{var | foo:「bar」}}中,過濾器foo將傳遞變數var和參數「bar」。 自定義filter程式碼文件擺放位置: app01/ __init__.py models.py templatetags/ # 在app01下面新建一個package package __init__.py app01_filters.py # 建一個存放自定義filter的py文件 views.py自定義過濾器流程
- 1 在app下創建一個名為templatetags的python包
#注意 在settings中的INSTALLED_APPS配置當前app,不然django無法找到自定義的simple_tag (模組名只能是templatetags)
- 2 在python中創建py文件,文件名可以自定義 如:(my_tags.py)
- 3 在py文件中寫:
from django import template register = template.Library() #固定寫法,不可改變
- 4 寫函數+裝飾器
@register.filter #過濾器 def add_str(value, arg): # 最多有兩個 return '{}-{}'.format(value, arg)- 5 寫頁面程式碼 在使用自定義simple_tag和filter的html文件中導入之前創建的 my_tags.py
{% load my_tags %} #先導入我們自定義那個文件 my_tags {{ name|add_str:age }} #參數只能是兩個,一個參數是變數name ,一個是參數是後面的那個參數age- 執行結果

- 自定義乘法過濾器 multioly
#過濾器函數 @register.filter def multiply1(value,arg): return value * arg #模板語句 {% load my_tags %} <p>{{ 6|multiply1:'6' }}</p> <p>{{ 6|multiply1:6 }}</p> <p>{{ '10'|multiply1:5 }}</p>- 執行結果


- 自定義除法過濾器 division
#過濾器函數 @register.filter def division(value,arg): return value / arg #模板語句 {% load my_tags %} <p>{{ 6|division:6 }}</p> <p>{{ 6|division:1 }}</p>- 執行結果

- 自定義除法過濾器 add
#過濾器函數 @register.filter def add(value,arg): return value + arg #可以這樣寫,但是轉換不了會報錯 int(value) + int(arg) #模板語句 {% load my_tags %} <p>{{ 6|add:6 }}</p> <p>{{ 6|add:0 }}</p> <p>{{ '鋼蛋g'|add:18 }}</p>- 執行結果


- 自定義減法過濾器 subtraction
#過濾器函數 @register.filter def add(value,arg): return value - arg #模板語句 {% load my_tags %} <p>{{ 6|add:6 }}</p> <p>{{ 6|add:0 }}</p>- 執行結果

自定義標籤 simpletag
- 與自定義過濾器區別,可以接受更多參數,使用標籤引用{{% %}
與自定義filter類似(也是在python包的templatetags文件下,創建此標籤),只不過接收更靈活的參數。 #simple_tag 程式碼 @register.simple_tag(name="plus") def plus(a, b, c): return "{} + {} + {}".format(a, b, c) #使用simple tag 自定義標籤 {% load app01_demo %} {# simple tag #} {% plus "1" "2" "abc" %} #例子 標籤程式碼 @register.simple_tag def join_str(*args, **kwargs): return '{} - {} '.format('*'.join(args), '$'.join(kwargs.values())) # 模板 {% load my_tags %} {% join_str '1' '2' '鋼蛋' k1='3' k2='4' %} - 執行效果

自定義標籤 inclusion_tag
- 多用於返回html程式碼片段 (動態變數 分頁)


- app文件下 創建python包

- 包文件名必須為 templatetags

- 在templatetags裡面創建任意 .py 文件

- 寫函數

- html頁面程式碼 #分頁顯示程式碼 <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% for i in num %} <li><a href="#">{{ i }}</a></li> {% endfor %} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> #頁面1 {% load my_tags %} {% page 5 %} #頁面2 {% load my_tags %} {% page 1 %}
- 顯示效果



- 總結:
自定義過濾器 filter 只能接受兩個參數 調用的時候使用 {{ filter }} 自定義標籤 simpletag 與自定義過濾器區別,可以接受更多參數,使用標籤引用{{% %} 自定義標籤 inclusion_tag 多用於返回html程式碼片段,使用標籤引用{{% %} csrf_token 跨站請求偽造保護
在頁面的form表單裡面寫上{% csrf_token %}- 如圖


靜態文件相關
#作用 在配置文件找到靜態文件別名,與文件地址進行拼接,這樣別名改了,也不會影響,靜態文件的導入 {% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!" /> #引用JS文件時使用: {% load static %} <script src="{% static "mytest.js" %}"></script> #某個文件多處被用到可以存為一個變數 {% load static %} {% static "images/hi.jpg" as myphoto %} <img src="{{ myphoto }}"></img> {% load static %} <link rel="stylesheet" href="{% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %}"> <link rel="stylesheet" href="{% static '/css/dsb.css' %}"> {% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %} {% get_static_prefix %} # 獲取別名- 獲取配置文件的 別名


母版和繼承
什麼是母版?
普通的HTML頁面 母版頁用於處理html頁面相同部分內容,避免出現冗餘程式碼,減少重複html頁面的編寫,提高程式碼復用性,方便程式碼修改.
繼承寫法
#在子頁面中在頁面最上方使用下面的語法來繼承母板。 {% extends '母版文件名.html' %}block 塊
通過在母板中使用{% block xxx %}來定義"塊"。 在子頁面中通過定義母板中的block名來對應替換母板中相應的內容。 #定義block {% block 塊名 %} {% endblock %} #還可以{{% endblock 塊名 %}}來關閉標籤,更加清新 #使用block {% block 塊名 %} #自己的內容 {% endblock %} #母版內容和自己內容都使用 {% block 塊名 %} #自己的內容 {% block.super %} {% endblock %}子頁面替換母版 block塊


- 注意事項
注意的點: 1. {% extends 'base.html' %} 寫在第一行 前面不要有內容 有內容會顯示 2. {% extends 'base.html' %} 'base.html' 加上引號 不然當做變數去查找 3. 把要顯示的內容寫在block塊中 4. 定義多個block塊,定義 css js 塊組件
#作用 可以將常用的頁面內容如導航條,頁尾資訊等組件保存在單獨的文件中,然後在需要使用的地方按如下語法導入即可。 #示列 單獨建一個html page <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% for i in num %} <li><a href="#">{{ i }}</a></li> {% endfor %} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> #別的頁面 引用 {% include 'page.html' %}作 者:郭楷豐