者 | 單雨
責(zé)編 | 胡巍巍
出品 | CSDN(ID:CSDNnews)
前言
為了實(shí)現(xiàn)模板封裝和復(fù)用,提高HTML界面調(diào)試便捷性以及前后端解耦等目標(biāo),Django定義了自己的網(wǎng)絡(luò)模板語言。
當(dāng)前介紹模板語言的官方文檔已經(jīng)非常完備,幾乎涵蓋了開發(fā)中需要用到的知識點(diǎn)和需要注意的問題,但同時官方文檔也存在一些問題:
翻譯不夠完善,帶來閱讀的困難;
一些知識點(diǎn)的介紹過于簡短,存在大量的頁內(nèi)鏈接,閱讀時需要跳轉(zhuǎn)到不同的頁面,閱讀不連貫。
本文基于官方文檔系統(tǒng)介紹了Django模板語言的基礎(chǔ)知識點(diǎn),方便快速了解Django模板語言。
模板系統(tǒng)設(shè)計哲學(xué)
Django的模板系統(tǒng)不是簡單的把Python嵌入到HTML中。
它的設(shè)計宗旨是:模板系統(tǒng)旨在展示內(nèi)容, 而不是程序邏輯,因此不在HTML頁面中嵌入Python。
簡單的說,模板只負(fù)責(zé)渲染數(shù)據(jù),大多數(shù)邏輯應(yīng)該交給視圖(view)進(jìn)行處理。
模板簡介
模板是一個簡單的文本文件。它可以生成任何基于文本的格式(如 HTML,XML,CSV等)。除了基本的HTML標(biāo)簽外,模板還包含兩種額外的元素——變量和標(biāo)簽。
模板中包含的變量可以被替換為變量的值,標(biāo)簽則被替換為相應(yīng)的模板控制邏輯。示例:
django
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
<h1>{{ section.title }}</h1>
{% for story in story_list %}
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}
`{{ section.title }}`在模板渲染時將會被變量的值替換,for標(biāo)簽可以實(shí)現(xiàn)模板的循環(huán)渲染。
基礎(chǔ)語法
變量
變量實(shí)現(xiàn)從模板上下文字典(返回HTTP響應(yīng)時傳遞過來的字典)中輸出一個值,這是一個類似于dict的對象,包含鍵值對。當(dāng)模板引擎遇到一個變量時,它會計算該變量,并用結(jié)果替換它。
變量名由字母、數(shù)字字符和下劃線("_")組成,但不能以下劃線開頭。點(diǎn)(".")也出現(xiàn)在變量中,代表屬性調(diào)用,變量名中不能有空格或標(biāo)點(diǎn)符號。
示例:
django
My first name is {{ first_name }}. My last name is {{ last_name }}.
當(dāng)傳入一個上下文字典`{'first_name': 'John', 'last_name': 'Doe'}`時,將會渲染得到:
django
My first name is John. My last name is Doe.
模板中的變量被字典中的值替換了。
變量還可以使用點(diǎn)表示法實(shí)現(xiàn)字典查找、屬性查找和列表索引查找等操作:
django
{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}
點(diǎn)表示法底層原理
當(dāng)模板系統(tǒng)遇到一個點(diǎn),它會按順序嘗試下面的動作:
1. 字典查詢
2. 屬性或方法查找
3. 數(shù)字索引查詢
如果結(jié)果值是可調(diào)用的,則調(diào)用該值時將不帶參數(shù),調(diào)用的結(jié)果成為新的模板值。
當(dāng)進(jìn)行能覆蓋字典查找的操作時,這種查找順序可能會造成一些意想不到的行為。例如:如果試圖循環(huán)一個collection .defaultdict字典對象:
django
{% for k, v in defaultdict.items %}
{其他操作}
{% endfor %}
因?yàn)樽值洳檎沂鞘紫劝l(fā)生的,所以這個行為會先提供一個默認(rèn)值,而不是使用預(yù)期的.items方法。在這種情況下,應(yīng)該首先考慮使用字典查找,而不是使用字典的屬性調(diào)用。
注意
屬性通常被解釋為一個文本字符串,防止和同名的變量沖突。例如{{foo.bar}}中的屬性“bar”將被解釋為一個文本字符串,如果模板上下文中存在變量“bar”,則不會使用該變量的值。
以下劃線開頭的變量屬性可能不能訪問,因?yàn)樗鼈兺ǔ1徽J(rèn)為是私有的。
如果引用不存在的變量,模板系統(tǒng)將插入string_if_invalid選項的值,該選項默認(rèn)設(shè)置為“”(空字符串)。
標(biāo)簽
標(biāo)簽在模板渲染過程中提供任意邏輯。標(biāo)簽可以輸出內(nèi)容,作為控制結(jié)構(gòu),例如“if”語句或“for”循環(huán),從數(shù)據(jù)庫獲取內(nèi)容,甚至允許訪問其他模板標(biāo)簽。
(1)標(biāo)簽聲明
標(biāo)簽的一般形式為:
django
{% tag %}
示例:
django
{% csrf_token %}
(2)傳入?yún)?shù)
django
{% cycle 'odd' 'even' %}
(3)成對使用的標(biāo)簽
有些標(biāo)簽需要開始和結(jié)束標(biāo)簽:
django
{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}
(4)常用標(biāo)簽
for:循環(huán)數(shù)組中的每個元素. 比如, 顯示列表 `athlete_list` 中每個元素的 `name` 屬性。
django
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
if 、elif和else:在上面,如果athlete_list不為空,則{{athlete_list|length}}變量將顯示運(yùn)動員的數(shù)量。
否則,如果athlete_in_locker_room_list不為空,則會顯示“Athletes should be out…”消息。如果兩個列表都為空,則顯示“No athletes”。
也可以在if標(biāo)簽里使用過濾器和各種操作符:
django
{% if athlete_list|length > 1 %}
Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
Athlete: {{ athlete_list.0.name }}
{% endif %}
注意
雖然上面的示例可以工作,但是要注意,大多數(shù)模板過濾器都返回字符串,因此使用過濾器進(jìn)行數(shù)學(xué)比較通常不會正常工作,而長度是個例外。
(5)更多
Django有很多內(nèi)置標(biāo)簽,更多關(guān)于內(nèi)置標(biāo)簽的信息請參考官方文檔:
https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/ref-templates-builtins-tags
如果需要編寫自定義標(biāo)簽,請參考官方文檔
https://docs.djangoproject.com/zh-hans/2.2/howto/custom-template-tags/howto-writing-custom-template-tags
如果需要對使用的標(biāo)簽和自定義的標(biāo)簽做一份說明文檔,可以使用Django提供的文檔工具,詳情請參考:
https://docs.djangoproject.com/zh-hans/2.2/ref/contrib/admin/admindocs/
過濾器
簡介
過濾器可以對變量做一些操作,例如給變量賦值,改變變量的值等。
修改變量顯示
過濾器可以修改變量的顯示。例如:
django
{{ name|lower }}
通過過濾器lower變量{{ name }}變?yōu)榱诵懽址?,通過管道符(|)間隔變量和過濾器來使用過濾器。
鏈?zhǔn)秸{(diào)用過濾器
一個過濾器的輸出可以作為下一個過濾器的輸入。
{{ text|escape|linebreaks }}是一種常用的轉(zhuǎn)換方式, 在這之后換行符被替換為了 <p> 標(biāo)簽。
轉(zhuǎn)換變量和標(biāo)簽參數(shù)
過濾器轉(zhuǎn)換變量和標(biāo)簽參數(shù)的值。示例:
django
{{ django|title }}
傳入`{'django': 'the web framework for perfecalist With deadline '}`上下文字典時,該模板呈現(xiàn)為:
django
The Web Framework For Perfectionists With Deadlines
傳入?yún)?shù)給過濾器
示例1:
django
{{ my_date|date:"Y-m-d" }}
my_date將會被替換為當(dāng)前日期。
示例2:
django
{{ bio|truncatewords:30 }}
將會會顯示 `bio` 變量的前30個字符
注意
過濾器參數(shù)中如果包含空格和標(biāo)點(diǎn)符號,必須使用引號“”括起來,例如,要用逗號和空格連接列表,可以使用{{list|join:", "}}。
Django提供了大約60個內(nèi)置模板過濾器,請參考官方文檔:
https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/ref-templates-builtins-filters,
下面列舉一些常用的過濾器:
default
如果變量為false或空,則使用給定的默認(rèn)值。否則,使用變量的值。例如:
django
{{ value|default:"nothing" }}
如果 `value` 沒有提供或者為空,那么將它顯示為 "`nothing`" 。
length
返回值的長度。這對字符串和列表都適用。例如:
django
{{ value|length }}
如果 `value` 為 `['a', 'b', 'c', 'd']`, 那么他將被顯示為 `4`。
filesizeformat
將值格式化為“人類可讀的”文件大小(即“13kb”、“4.1 MB”、“102字節(jié)”等)。例如:
django
{{ value|filesizeformat }}
如果值為123456789,則輸出為117.7 MB。
如果需要自定義過濾器,請參考請官方文檔:
https://docs.djangoproject.com/zh-hans/2.2/howto/custom-template-tags/
注釋
示例:
單行注釋
django
{ this won't be rendered }
多行注釋:{% comment %} 和{% endcomment %}
django
<p>Rendered text with {{ pub_date|date:"c" }}</p>
{% comment "Optional note" %}
<p>Commented out text with {{ create_date|date:"c" }}</p>
{% endcomment %}
注意:Comment標(biāo)簽不能嵌套使用。
作者簡介:單雨,90后工科男,偽文藝青年。目前就讀于北京理工大學(xué)宇航系,喜歡研究AI,網(wǎng)絡(luò)爬蟲,微信小程序以及機(jī)器人,癡迷于Coding,睡前必擼碼。
【END】
直接寫在template屬性里面,這種寫法比較直觀,適用于html代碼不多的場景,但如果html代碼很多,就不方便維護(hù)了,所以如果代碼多就不建議這么寫:
在template屬性里寫模版id,這種和上面的寫法很像,只不過單獨(dú)把html的內(nèi)容移到template標(biāo)簽里面,寫起來就像正常的html一樣,還有代碼提示
在一個 <script> 元素中,并為其帶上 text/x-template 的類型,然后通過一個 id 將模板引用過去
以上就是介紹的幾種模版寫法。
//別忘了引包
<body>
<div id="app-1">
{{msg}}
</div>
================
<div id="app-2">
{{msg}}
</div>
=================
<div id="app-3">
{{msg}}
</div>
<script>
//在vue.js中,可以使用template給元素添加模板,但是元素中只能有一個根元素,不能出現(xiàn)兩個或兩個以上的根同級元素。還可以在模板中綁定數(shù)據(jù)、表達(dá)式等。下面利用實(shí)例說明如何添加模板
// 創(chuàng)建 Vue 實(shí)例,得到 ViewModel
new Vue({
el: '#app-1',
data: {
msg:'這是通過el屬性獲取掛載元素的outerHTML方式渲染'
}
});
//結(jié)論:如果vue實(shí)例中有template屬性,會將該屬性值進(jìn)行編譯,將編譯后的虛擬dom直接替換掉vue實(shí)例綁定的元素(即el綁定的那個元素);
//注意:template屬性中的dom結(jié)構(gòu)只能有一個根元素,如果有多個根元素需要使用v-if、v-else、v-else-if設(shè)置成只顯示其中一個根元素;
new Vue({
el: '#app-2',
data: {
msg:'這是通過el屬性獲取掛載元素的outerHTML方式渲染'
},
template:'<div>這是template屬性模板渲染</div>'
});
//render
new Vue({
el: '#app-3',
data: {
msg:'這是通過el屬性獲取掛載元素的outerHTML方式渲染'
},
template:'<div>這是template屬性模板渲染</div>',
render: function(createElement){
return createElement('div',
// 參數(shù)2、這里相當(dāng)于給標(biāo)簽加屬性 例如:<div style='color:red,font-size: 14px'></div>
{
//給div綁定樣式
style:{
width:'300px',
height:'400px',
color:'pink'
},
//給div綁定點(diǎn)擊事件
on: {
click: () => {
console.log('點(diǎn)擊事件')
}
}
},
// 參數(shù)3、參數(shù)中渲染的標(biāo)簽的子元素數(shù)組(可選)
// [
// // 文本節(jié)點(diǎn)直接寫就可以
// 'text'
// ]
'這是render屬性方式渲染。'
);
}
});
</script>
</body>
終極結(jié)論
el,template,render屬性優(yōu)先性
當(dāng)Vue選項對象中有render渲染函數(shù)時,Vue構(gòu)造函數(shù)將直接使用渲染函數(shù)渲染DOM樹,當(dāng)選項對象中沒有render渲染函數(shù)時,Vue構(gòu)造函數(shù)首先通過將template模板編譯生成渲染函數(shù),然后再渲染DOM樹,而當(dāng)Vue選項對象中既沒有render渲染函數(shù),也沒有template模板時,會通過el屬性獲取掛載元素的outerHTML來作為模板,并編譯生成渲染函數(shù)。
換言之,在進(jìn)行DOM樹的渲染時,render渲染函數(shù)的優(yōu)先級最高,template次之且需編譯成渲染函數(shù),而掛載點(diǎn)el屬性對應(yīng)的元素若存在,則在前兩者均不存在時,其outerHTML才會用于編譯與渲染。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。