Django 模版語法與使用
目錄
- Django 模版語法與使用
- django模板語言介紹 (摘自官方文檔) 鏈接
- 什么是模板?
- 模板語句的 注釋
- 變量 {{ 變量 }}
- 點(.)在模板語言中有特殊的含義,用來獲取對象的相應屬性值。
- Tags 標簽 {% %} 表示邏輯相關的操作
- for循環可用的一些參數:
- Filters 過濾器
- 設置除法除盡 divisibleby:參數
- with 的使用
- default 系統默認值
- filesizeformat 文件大小人性化顯示
- add "加"
- lower 小寫
- upper 大寫
- title 標題
- ljust 左對齊
- rjust 右對齊
- center 居中
- length 長度
- slice 切片
- first 取第一個元素
- last 取最后一個元素
- join 使用字符串拼接列表
- cut 移除value中所有的與給出的變量相同的字符串
- truncatechars 按照字符截斷 ...也計數
- date 日期格式化
- safe 防止xss攻擊 作用 取消轉義
- safe 主要作用
- 也可以導入模塊實現這種效果
- 自定義 filter
- 自定義標簽 simpletag
- 自定義標簽 inclusion_tag
- csrf_token 跨站請求偽造保護
- 靜態文件相關
- 母版和繼承
- 組件
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 MB
add "加"
- 給變量加參數,字符串默認嘗試轉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' %}