04 Django之模板系统
一.語法
關(guān)于模板渲染只需要記住兩種特殊符號(hào)(語法):
{{ }} 和 {% %}? (變量相關(guān)用{{ }}? 邏輯相關(guān)用{% %})
二.變量
在Django的模板語言中按照{(diào){ 變量名 }}來使用.
當(dāng)模板引擎遇到一個(gè)變量,它將計(jì)算這個(gè)變量,然后用結(jié)果替換掉它的本身
注意事項(xiàng)
1.如果計(jì)算結(jié)果的值是可調(diào)用的,它將被無參數(shù)的調(diào)用.調(diào)用的結(jié)果將成為模板的值.
2.如果使用的變量不存在,模板系統(tǒng)將插入string_if_invalid選項(xiàng)的值,它被默認(rèn)設(shè)置為"(空字符串)"
例子:
views.py? 中的代碼
def index(request):import datetimes = "hello"l = [111, 222, 333] # 列表dic = {"name": "yuan", "age": 18} # 字典date = datetime.date(1993, 5, 2) # 日期對(duì)象class Person(object):def __init__(self, name):self.name = namedef dream(self):return 'dreamer'person_yuan = Person("chao") # 自定義類對(duì)象person_egon = Person("yantao")person_alex = Person("jinxin")person_list = [person_yuan, person_egon, person_alex]return render(request, "index.html", {"l": l, "dic": dic, "date": date,"person_list": person_list})# return render(request,'index.html',locals())#locals()獲取函數(shù)內(nèi)容所有的變量,然后通過render方法給了index.html文件進(jìn)行模板渲染,
如果你圖省事,你可以用它,但是很多多余的變量也被傳進(jìn)去了,效率低
模板中的寫法:
<h4>{{s}}</h4> <h4>列表:{{ l.0 }}</h4> <h4>列表:{{ l.2 }}</h4> <h4>字典:{{ dic.name }}</h4> <h4>日期:{{ date.year }}</h4><!--取列表的第1個(gè)對(duì)象的name屬性的值--> <h4>類對(duì)象列表:{{ person_list.0.name }}</h4> <!--取列表的第1個(gè)對(duì)象的dream方法的返回值,如果沒有返回值,拿到的是none--> <h4>類對(duì)象列表:{{ person_list.0.dream }}</h4>注意:調(diào)用對(duì)象里面的方法的時(shí)候,不需要寫括號(hào)來執(zhí)行,并且執(zhí)行不需要傳參數(shù)的方法,如果你的這個(gè)方法需要傳參數(shù),那么模板語言不支持,不能幫你渲染
三.過濾器
在Django的模板語言中,通過使用 過濾器來改變變量的顯示.
過濾器的語法: {{ vlaue|filter_name:參數(shù)}}
使用管道符來應(yīng)用過濾器
例如:{{ name|lower }} 會(huì)將name變量應(yīng)用lower過濾器之后再顯示它的值.lower的作用是將文本全部變成小寫.
注意事項(xiàng):
default?
如果一個(gè)變量是false或者為空,使用給定的默認(rèn)值,否則,使用變量的值
{{ value|default:"nothing"}}如果value沒有傳值或者值為空的時(shí)候就顯示nothing
length
返回值的長度,作用于字符串和列表.
{{ value|length}}
返回value的長度,如value=['a',?'b',?'c',?'d']的話,就顯示4.
filesizeformat
將值格式化為一個(gè)"人類可讀的"文件尺寸? (例如:?'13 KB',?'4.1 MB',?'102 bytes', 等等).
{{ value|filesizeformat}}如果 value 是 123456789,輸出將會(huì)是 117.7 MB。
slice
切片,如果value="hello world" ,還有其他可切片的數(shù)據(jù)類型
{{value|slice:"2:-1"}}date
格式化,如果value=datetime.datetime.now()
{{ value|date:"Y-m-d H:i:s"}}關(guān)于時(shí)間日期的可用的參數(shù)(除了Y,m,d等等)還有很多
safe
Django的模板中在進(jìn)行模板渲染的時(shí)候會(huì)對(duì)HTML標(biāo)簽和JS等語法標(biāo)簽進(jìn)行自動(dòng)轉(zhuǎn)義,原因顯而易見,這樣是為了安全,django擔(dān)心這是用戶添加的數(shù)據(jù),比如如果有人給你評(píng)論的時(shí)候?qū)懥艘欢蝚s代碼,這個(gè)評(píng)論一提交,js代碼就執(zhí)行啦,這樣你是不是可以搞一些壞事兒了,寫個(gè)彈窗的死循環(huán),那瀏覽器還能用嗎,是不是會(huì)一直彈窗啊,這叫做xss攻擊,所以瀏覽器不讓你這么搞,給你轉(zhuǎn)義了。但是有的時(shí)候我們可能不希望這些HTML元素被轉(zhuǎn)義,比如我們做一個(gè)內(nèi)容管理系統(tǒng),后臺(tái)添加的文章中是經(jīng)過修飾的,這些修飾可能是通過一個(gè)類似于FCKeditor編輯加注了HTML修飾符的文本,如果自動(dòng)轉(zhuǎn)義的話顯示的就是保護(hù)HTML標(biāo)簽的源文件。為了在Django中關(guān)閉HTML的自動(dòng)轉(zhuǎn)義有兩種方式,如果是一個(gè)單獨(dú)的變量我們可以通過過濾器“|safe”的方式告訴Django這段代碼是安全的不必轉(zhuǎn)義。
我們?nèi)etwork那個(gè)地方看看,瀏覽器看到的都是渲染之后的結(jié)果,通過network的response的那個(gè)部分可以看到,這個(gè)a標(biāo)簽全部是特殊符號(hào)包裹起來的,并不是一個(gè)標(biāo)簽,這都是django搞得事情。
比如:
value = "<a href='#'>點(diǎn)我</a>"? ?和? ?value="<script>alert('123')</script>"
{{ value|safe}}truncatechars
如果字符串字符多于指定的字符數(shù)量,那么會(huì)被截?cái)?截?cái)嗟淖址畬⒖梢苑g的圣羅浩代替("...")結(jié)尾
參數(shù):截端的字符數(shù)
{{ value|truncatechars:9}} #注意:最后那三個(gè)省略號(hào)也是9個(gè)字符里面的,也就是這個(gè)9截?cái)喑鰜淼氖?個(gè)字符+3個(gè)省略號(hào),有人會(huì)說,怎么展開啊,配合前端的點(diǎn)擊事件就行啦
truncatewords
在一定的數(shù)量的字后面截?cái)嘧址?是截?cái)喽嗌賯€(gè)單詞
例如:‘hello girl hi baby yue ma’,
{{ value|truncatewords:3}} #上面例子得到的結(jié)果是 'hello girl h1...'cut
移除value中所有的與給出的變量相同的字符串
{{ value|cut:' ' }}join
使用字符串連接列表,{{ list|join:', ' }},就像Python的str.join(list)
四 標(biāo)簽Tags
標(biāo)簽看起來像是{% tag %}. 標(biāo)簽比變量更復(fù)雜:一些在輸出中創(chuàng)建文本,一些通過循環(huán)或邏輯來控制流程,一些加載其后的變量將使用到的額外信息到模板中.一些標(biāo)簽需要開始和結(jié)束標(biāo)簽(例如{% tag %} ...標(biāo)簽 內(nèi)容 ... {% endtag %})。
? for標(biāo)簽
遍歷每一個(gè)元素:寫一個(gè)for,然后tab鍵自動(dòng)生成for循環(huán)的結(jié)構(gòu),沒有break之類的,復(fù)雜一些的功能,需要通過js
{% for person in person_list %}<p>{{ person.name }}<p> <!--凡是變量就都要用兩個(gè)大括號(hào)括起來-->{% endfor %}
? 可以利用{%?for?obj?in?list?reversed?%}反向完成循環(huán)。
遍歷字典
{% for key,val in dic.items %}<p>{{ key }}:{{ val }}<p> {% endfor %}注:循環(huán)序號(hào)可以通過{{forloop}}顯示,必須在循環(huán)內(nèi)部用
forloop.counter 當(dāng)前循環(huán)的索引值(從1開始),forloop是循環(huán)器,通過點(diǎn)來使用功能 forloop.counter0 當(dāng)前循環(huán)的索引值(從0開始) forloop.revcounter 當(dāng)前循環(huán)的倒序索引值(從1開始) forloop.revcounter0 當(dāng)前循環(huán)的倒序索引值(從0開始) forloop.first 當(dāng)前循環(huán)是不是第一次循環(huán)(布爾值) forloop.last 當(dāng)前循環(huán)是不是最后一次循環(huán)(布爾值) forloop.parentloop 本層循環(huán)的外層循環(huán)的對(duì)象,再通過上面的幾個(gè)屬性來顯示外層循環(huán)的計(jì)數(shù)等for ... empty
for標(biāo)簽帶有一個(gè)可選的{% empty %}從句,以便在給出的組是空的或者沒有被找到時(shí),可以有所操作.
{% for person in person_list %}<p>{{ person.name }}</p>{% empty %}<p>sorry,no person here</p> {% endfor %}if 標(biāo)簽
{% if %}會(huì)對(duì)一個(gè)變量求值,如果它的值是"True"(存在,不為空,且不是boolean類型的false值),對(duì)應(yīng)的內(nèi)容塊會(huì)輸出.
{% if num > 100 or num < 0 %}<p>無效</p> <!--不滿足條件,不會(huì)生成這個(gè)標(biāo)簽--> {% elif num > 80 and num < 100 %}<p>優(yōu)秀</p> {% else %} <!--也是在if標(biāo)簽結(jié)構(gòu)里面的--><p>湊活吧</p> {% endif %}當(dāng)然也可以只有if和else
{% if user_list|length > 5%} 結(jié)合過濾器來使用七座豪華SUV {% else %}黃包車 {% endif %}if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,注意條件兩邊都有空格。
? with?
使用一個(gè)簡單的名字緩存一個(gè)復(fù)雜的變量,多用于給一個(gè)復(fù)雜的變量起別名,當(dāng)你需要使用一個(gè)"昂貴的方法"(比如訪問數(shù)據(jù)庫)很多次的時(shí)候是很有用的
例如:
等號(hào)左右不要加空格
{% with total=business.employees.count%}{{ total }} 只能在with語句體里使用 {% endwith %}或者
{% with business.employees.count as total %}{{ total}} {% endwith %}csrf_token
我們以post方式提交表單的時(shí)候,會(huì)報(bào)錯(cuò),還記得我們?cè)趕ettings里面的中間件配置里面把一個(gè)csrf的防御機(jī)制給注銷了啊,本身不應(yīng)該注銷的,而是應(yīng)該學(xué)會(huì)怎么使用它,并且不讓自己的操作被forbiden,通過這個(gè)東西就能搞定。
這個(gè)標(biāo)簽用于跨站請(qǐng)求偽造保護(hù)
? 在頁面的form表單里面(注意是在form表單里面)任何位置寫上{% csrf_token %},這個(gè)東西模板渲染的時(shí)候替換成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隱藏的,這個(gè)標(biāo)簽的值是個(gè)隨機(jī)字符串,提交的時(shí)候,這個(gè)東西也被提交了,首先這個(gè)東西是我們后端渲染的時(shí)候給頁面加上的,那么當(dāng)你通過我給你的form表單提交數(shù)據(jù)的時(shí)候,你帶著這個(gè)內(nèi)容我就認(rèn)識(shí)你,不帶著,我就禁止你,因?yàn)楹笈_(tái)我們django也存著這個(gè)東西,和你這個(gè)值相同的一個(gè)值,可以做對(duì)應(yīng)驗(yàn)證是不是我給你的token,存儲(chǔ)這個(gè)值的東西我們后面再學(xué),你先知道一下就行了,就像一個(gè)我們后臺(tái)給這個(gè)用戶的一個(gè)通行證,如果你用戶沒有按照我給你的這個(gè)正常的頁面來post提交表單數(shù)據(jù),或者說你沒有先去請(qǐng)求我這個(gè)登陸頁面,而是直接模擬請(qǐng)求來提交數(shù)據(jù),那么我就能知道,你這個(gè)請(qǐng)求是非法的,反爬蟲或者惡意攻擊我的網(wǎng)站,以后將中間件的時(shí)候我們?cè)诩?xì)說這個(gè)東西,但是現(xiàn)在你要明白怎么回事,明白為什么django會(huì)加這一套防御。
?五 模板繼承
Django模板引擎中最強(qiáng)大的也是最復(fù)雜的部分就是模板繼承.模板繼承可以讓你創(chuàng)建一個(gè)基本的骨架模板,它包含您站點(diǎn)的全部元素,并且可以定義能夠被子木板覆蓋的blocks.
<!DOCTYPE html> <html lang="en"> <head><link rel="stylesheet" href="style.css" /><title>{% block title %}My amazing site{%/span> endblock %}</title> </head><body><div id="sidebar">{% block sidebar %}<ul><li><a href="/">Home</a></li><li><a href="/blog/">Blog</a></li></ul>{% endblock %}</div><div id = "content">{% block content %} {% endblock %}</div> </body> </html>對(duì)標(biāo)簽設(shè)置id屬性? 然后{% block id屬性名字%}
?
這個(gè)模版,我們把它叫作?base.html, 它定義了一個(gè)可以用于兩列排版頁面的簡單HTML骨架。“子模版”的工作是用它們的內(nèi)容填充空的blocks。
在這個(gè)例子中,?block?標(biāo)簽定義了三個(gè)可以被子模版內(nèi)容填充的block。?block?告訴模版引擎: 子模版可能會(huì)覆蓋掉模版中的這些位置。
子模版可能看起來是這樣的:
{% extends "base.html"%}{% block title %}My amazing blog{% endblock %}{% block content %} {% for entry in blog_entries %}<h2>{{ entry.title }}</h2><p>{{ entry.body }}</p> {% endfor %} {% endblock %}extends標(biāo)簽是關(guān)鍵,他告訴模板引擎,這個(gè)模板"繼承"了另一個(gè)模板.當(dāng)模板系統(tǒng)處理這個(gè)模板的時(shí)候,首先,它將定位父模板----就是base.html
請(qǐng)注意,子模版并沒有定義?sidebar?block,所以系統(tǒng)使用了父模版中的值。父模版的?{% block %}?標(biāo)簽中的內(nèi)容總是被用作備選內(nèi)容(fallback)。
這種方式使代碼得到最大程度的復(fù)用,并且使得添加內(nèi)容到共享的內(nèi)容區(qū)域更加簡單,例如,部分范圍內(nèi)的導(dǎo)航。
這里是使用繼承的一些提示:
-
如果你在模版中使用?{% extends %}?標(biāo)簽,它必須是模版中的第一個(gè)標(biāo)簽。其他的任何情況下,模版繼承都將無法工作,模板渲染的時(shí)候django都不知道你在干啥。
-
在base模版中設(shè)置越多的?{% block %}?標(biāo)簽越好。請(qǐng)記住,子模版不必定義全部父模版中的blocks,所以,你可以在大多數(shù)blocks中填充合理的默認(rèn)內(nèi)容,然后,只定義你需要的那一個(gè)。多一點(diǎn)鉤子總比少一點(diǎn)好。
-
如果你發(fā)現(xiàn)你自己在大量的模版中復(fù)制內(nèi)容,那可能意味著你應(yīng)該把內(nèi)容移動(dòng)到父模版中的一個(gè)?{% block %}?中。
-
為了更好的可讀性,你也可以給你的?{% endblock %}?標(biāo)簽一個(gè)?名字?。例如:
? 在大型模版中,這個(gè)方法幫你清楚的看到哪一個(gè) ?{% block %}?標(biāo)簽被關(guān)閉了。
- 不能在一個(gè)模版中定義多個(gè)相同名字的?block?標(biāo)簽。
六 組件
可以將常用的頁面如導(dǎo)航條,頁尾信息等組件保存在單獨(dú)的文件中,然后在需要使用的地方,文件的任意位置按如下語法導(dǎo)入即可
{% include 'navbar.html' %}例如:有個(gè)如下的導(dǎo)航欄,nav.html:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><style>.c1{background-color: red;height: 40px;}</style> </head> <body><div class="c1"><div><a href="">xx</a><a href="">dd</a></div> </div></body> </html>嵌入導(dǎo)航欄的頁面,test.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> {% include 'nav.html' %} <h1>xxxxxxxxxx</h1> </body> </html>?七 自定義標(biāo)簽和過濾器
1. 在setting中的INSTALLED_APPS配置當(dāng)前的app,不然django無法找到自定義的simple_tag
2.在app中創(chuàng)建templatetags模塊(模塊只能是templatetags)
3.創(chuàng)建任意.py文件
from django import template from django.untils.safestring import mark_saferegister = template.Library() #register的名字是固定的,不可以改變@register.filter def filter_multi(v1,v2):return v1*v2@register.simple_tag #和自定義filter類似,只不過接受更靈活的參數(shù),沒有個(gè)數(shù)限制def simple_tag_multi(v1,v2):return v1*v2@registe.simple_tag def my_input(id,arg):result = "<input type='text' id='%s' class='%s' />" %(id,arg,)return mark_safe(result)4. 在使用自定義simple_tag和filter的html文件中導(dǎo)入之前創(chuàng)建的my_tags.py
{% load my_tags%}5 使用simple_tag和filter(如何調(diào)用)
-------------------------------------------------------------.html {% load xxx%}#num = 12 {{ num|filter_muti:2}} #24{{ num|filter_multi:"[22,333,4444]"}}{{% simple_tag_multi 2 5 %}} 參數(shù)不限,但是不能放for 和 if循環(huán) {% simple_tag_multi num 5 %}注意:filter可以用在if.for等語句后,simple_tag不可以
{% if num|filter_multi:30 > 100 %}{{ num|filter_multi:30 }} {% endif %}inclusion_tag
多用于返回html代碼片段
示例:
templatetags/my_inclusion.py
from django import templateregister = template.Library()@register.inclusion_tag('result.html') #將result.html里面的內(nèi)容用下面函數(shù)的返回值渲染,然后作為一個(gè)組件一樣,加載到使用這個(gè)函數(shù)的html文件里面 def show_result(n):#參數(shù)可以傳多個(gè)進(jìn)來n = 1 if n < 1 else int(n)data = ["第{}項(xiàng)".format(i) for i in range(1,n+1)]return {"data":data} #這里可以傳多個(gè)值,和render的感覺是一樣的 {'deta1':data1,
'data2':data2.....}
templates/snippets/result.html
<ul>{% for choice in data %}<li>{{ choice }}</li>{% endfor %} </ul>templates/index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>inclusion_tag test</title> </head> <body>{% load inclusion_tag_test %}{% show_results 10 %} </body> </html>
?
轉(zhuǎn)載于:https://www.cnblogs.com/a2534786642/p/10444934.html
總結(jié)
以上是生活随笔為你收集整理的04 Django之模板系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10774: matrix
- 下一篇: 几种网站后门排查 不全面