Django模板層
模板層的主要任務就是如何將頁面呈現給使用者,使用者能看到的所有東西都是屬於模板層進行呈現的。
HTML
檔案就是模板,模板是會先經過渲染,再呈現給使用者。
學習模板層主要有以下兩點:
變數相關或處理均使用
{{}}
,即模板變數。邏輯相關或處理均使用
{%%}
,即模板標籤。
模板變數傳值
其實在聊Django
檢視層的時候介紹的render()
方法中就允許將檢視函式中的變數傳遞給模板。
模板中使用{{name}}
即可完成呼叫。
def test(request):
username = "雲崖先生"
return render(request,"test.html",locals())
<body>
{{username}}
</body>
傳值型別
Python
中所有基本資料型別均可以進行模板傳遞,但是函式、類等可呼叫型別會出現一些令人意外的情況。
注意:可呼叫型別傳遞時會自動加括號呼叫,並將返回值進行渲染(如果沒有返回值則為
None
),但是不支援引數的傳遞。
後端返回:
def test(request):
STR = "雲崖先生"
INT = 100
FLOAT = 11.11
BOOL = True
DICT = {"v1":"k1"}
SET = {"1","2","3"}
TUPLE = (1,2,3)
LIST = [1,2,3,4]
def func():
return "function"
class T1(object):
pass
return render(request,"test.html",locals())
模板接收:
<body>
<p>{{STR}}</p>
<p>{{INT}}</p>
<p>{{FLOAT}}</p>
<p>{{BOOL}}</p>
<p>{{DICT}}</p>
<p>{{SET}}</p>
<p>{{TUPLE}}</p>
<p>{{LIST}}</p>
<p>{{func}}</p> <!-- 不支援引數傳遞 -->
<p>{{T1}}</p> <!-- 例項化出了一個類 -->
</body>
渲染結果:
雲崖先生
100
11.11
True
{'v1': 'k1'}
{'1', '2', '3'}
(1, 2, 3)
[1, 2, 3, 4]
function
<app01.views.test.<locals>.T1 object at 0x000001C1E00ACB38>
元素取出
無論後端的變數是list
或者dict
,均可使用.
語法進行取值。
傳值:
def test(request):
DICT = {"hobby":["basketball","football","volleyball"]}
return render(request,"test.html",locals())
取值:
{{DICT.hobby.2}}
結果:
volleyball
模板變數過濾
由於後端的函式模板中使用函式無法傳遞引數,所以提供自帶的過濾器進行操作。
過濾器有非常多的功能,大概有六十多種過濾器提供使用,這裡只介紹常用的。
使用示例
以下舉例常用的模板過濾器
過濾器 | 描述 |
---|---|
{{v1|length}} | 獲取v1的長度 |
{{v1|default:v2}} | 如果v1為真,則使用v1,否則使用v2 |
{{v1|filesizeformat}} | v1必須是int型別,對其進行KB、MB、GB、TB 等進位制之間的轉換 |
{{v1|date:"Y-m-d X"}} | v1必須是時間型別,對其進行自定義格式化 |
{{v1|slice:"start:stop:step"}} | v1必須是可通過索引取值的型別,對其進行切片 |
{{v1|truncatechars:num}} | v1必須是可通過索引取值的型別,對其擷取指定長度的字元(包含三個. ) |
{{v1|truncatewords:num}} | v1必須是字串型別,對其進行擷取特點數量的單詞,以空格分隔(不包含. ) |
{{v1|cut:'v2'}} | 移除v1中特定的字元v2 |
{{v1|join:'v2'}} | 使用v2對v1進行拼接 |
{{v1|add:v2}} | v1與v2進行相加,如都是int則為加法,如都是str則為拼接 |
{{v1|safe}} | 識別v1中的HTML程式碼並進行渲染(預設不會進行渲染) |
後端返回:
def test(request):
import datetime
v_1 = "12345"
v_2 = False
v_3 = 10240
v_4 = datetime.datetime.now()
v_5 = ["一","二","三","四","五","六","七"]
v_6 = "abcdefghijklmn"
v_7 = "HELLO WORD HELLO DJANGO"
v_8 = "ABC$$$"
v_9 = "QWETYU"
v_10 = 10
v_11 = "<h1>標題一<h1>"
return render(request,"test.html",locals())
模板接收加過濾:
<body>
<p>{{v_1|length}}</p>
<p>{{v_2|default:1}}</p>
<p>{{v_3|filesizeformat}}</p>
<p>{{v_4|date:"Y-m-d h:m:s"}}</p>
<p>{{v_5|slice:"1:4:2"}}</p>
<p>{{v_6|truncatechars:6}}</p>
<!-- 上面的: 三個點佔三個位置 -->
<p>{{v_7|truncatewords:3}}</p>
<!-- 上面的:三個點不佔位置 -->
<p>{{v_8|cut:"$"}}</p>
<p>{{v_9|join:"---"}}</p>
<p>{{v_10|add:10}}</p>
{{v_11|safe}}
</body>
渲染結果:
後端渲染
預設的,後端如果返回HTML
程式碼模板層是不會進行渲染的,這是為了防止XSS
攻擊。
但是如果使用mark_safe()
進行包裹,則會進行渲染。
def test(request):
from django.utils.safestring import mark_safe # 匯入模組
res = "<h1>不會渲染<h1>"
res_safe = mark_safe("<h1>會渲染<h1>")
return render(request,"test.html",locals())
<body>
{{res}}
{{res_safe}}
</body>
模板標籤分支
基本使用
模板中支援對{% if %}、{% else %}、{% elif %}
進行使用,與Python
中邏輯一致。
注意:判斷完成後要使用
{% endif %}
進行結束判斷的標誌
<body>
{% if user %} <!-- 在{%%}的模板標籤中,被{{}}套住的變數可以不用寫{{}}-->
<p>有內容</p>
{% else %}
<p>無內容</p>
{% endif %}
</body>
模板標籤迴圈
基本使用
模板中支援{% for %}
來進行操作。
注意:迴圈完成後要使用
{% endfor %}
進行結束迴圈的標誌
li = ["A","B","C"]
<body>
{% for row in li %}
<p> {{row}} </p> <!-- 在{%%}外使用變數,依然要巢狀上{{}} -->
{% endfor %}
</body>
A
B
C
forloop
{{forloop}}
記錄了一些迴圈的資訊。
如下所示:
li = ["A","B","C"]
<body>
{% for row in li %}
<p> {{forloop}} </p> <!-- 可使用 {{forloop.counter/first/last}} 等 -->
{% endfor %}
</body>
不可迴圈
如果一個迭代物件為空,則不可迴圈。此時可以使用{% empty %}
進行操作
li = []
<body>
{% for row in li %}
<p>不為空</p>
{% empty %}
<p>迭代物件為空</p> <!--執行這裡-->
{% endfor %}
</body>
鍵值方法
在迴圈中,可以對被遍歷的物件使用keys、values、items
進行操作。
這與Python
中是一樣的。
dic = {"name":"雲崖","age":"18","gender":"男",}
<body>
{% for key in dic.keys %}
<p>{{key}}</p>
{% endfor %}
{% for value in dic.values %}
<p>{{value}}</p>
{% endfor %}
{% for kv in dic.items %}
<p>{{kv}}</p>
{% endfor %}
</body>
----------------
name
age
gender
----------------
雲崖
18
男
----------------
('name', '雲崖')
('age', '18')
('gender', '男')
模板標籤別名
可以使用{% with %}
配合as
對巢狀複雜的單項資料做一個別名。方便後續進行拿出,更推薦與迴圈進行配套使用。
li = [
{"username":"Yunya"},
{"username":"Jack"},
{"username":"Tom"},
]
----------------
<body>
{% for row in li %}
{% with row.username as data %}
<p>{{data}}</p>
<!-- 如果不使用別名,則需要寫 {{row.username}} 這只是一個示例,實際的巢狀可能比這個複雜的多 -->
{% endwith %}
{% endfor %}
</body>
----------------
Yunya
Jack
Tom
自定義系列
所有的,自定義都需要完成以下三步驟:
1.在
APP
中建立templatetags
資料夾,必須叫這個名字2.在該資料夾下建立一個
py
檔案,可以是任意名字3.匯入一個模組,並寫一句話
from django import template
register = template.Library()
自定義過濾器
先完成上面三步,再進行過濾器的建立。
自定義過濾器的作用就是豐富內建的過濾器,完成你的需求。
注意:過濾器的呼叫是
{{ v1|filter:v2 }}
,過濾器最多隻能傳遞兩個引數,且第一個引數在|
左邊,第二個引數傳遞的格式必須是過濾器名字:
右邊的引數。
自定義過濾器全步驟:
# app01/templatetags/tags.py
from django import template
register = template.Library()
@register.filter(name="f1") # 在使用時,使用的是這個名字。函式名可以隨便取。注意一定要關鍵字傳參
def f1(left, right): # left 代表斜槓左邊的值,right代表斜槓右邊的值
return left + right
基本使用:
<body>
{% load tags %} <!-- 先匯入標籤的檔案,tags.py -->
{{1|f1:2}} <!-- 最多兩個引數,引數1|過濾器名字:引數2 這是固定格式
</body>
-------
3
自定義標籤
自定義標籤與自定義過濾器比較相似但是也有兩大不同。
1.支援無限制的引數傳遞
2.引數傳遞方式不同
注意:標籤的呼叫是
{% tag v1 v2 v3 %}
,這與過濾器有較大的不同。
先完成上面三步,再進行標籤的建立。
# app01/templatetags/tags.py
from django import template
register = template.Library()
@register.simple_tag(name="t1") # 在使用時,使用的是這個名字。函式名可以隨便取。注意一定要關鍵字傳參
def t1(v1, v2, v3):
return v1 + v2 + v3
基本使用:
<body>
{% load tags %} <!-- 先匯入標籤的檔案,tags.py -->
{% t1 1 2 3%} <!--引數無限制-->
</body>
自定義inclusion_tag
自定義inclusion_tag
與上面兩個都不太一樣,它返回的是一個區域性頁面,當你的專案中有很多網頁中都有相同的一部分網頁結構,則使用自定義inclusion_tag
來完成。
還是需要先完成上面三個步驟。
# app01/templatetags/tags.py
from django import template
register = template.Library()
@register.inclusion_tag("common.html") # 去根目錄找templates資料夾下的common.html檔案
def common_html(username): # 注意,這裡呼叫是函式名,而不是上面指定的名字了
user = username
return locals() # 返回當前名稱空間中所有變數名
# 專案根目錄/templats/common.html
<h1>當前登入:{{user}}</h1> # 可以拿到 common_html 函式中的所有變數名了
<h1>點選登出</h1>
# 被渲染的模板
<body>
{% load tags %}
{% common_html "雲崖" %} <!---這一處將會替換為指定的頁面,即common.html裡的內容-->
</body>
模板繼承引入
模板繼承
模板繼承是全棧開發裡面Django
所提供的非常牛逼的一個功能,它允許你一套HTML
模板能被其他模板進行繼承並修改一些特定區域的內容。
# 專案根目錄/templats/common.html
{% block left %}
<!-- 這裡面可以允許修改,相當於給這塊區域起一個名字,left -->
{% endblock %}
============================
# 專案根目錄/templats/other.html
{% extends 'common.html' %}
<!-- 繼承common.html -->
{% block left %}
<!-- 執行修改 -->
{% endblock %}
接下來看一下演示程式碼就知道了。
這裡放一套公用的左右佈局頁面
# 專案根目錄/templats/common.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src='https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js'></script>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css'
integrity='sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u' crossorigin='anonymous'>
<script src='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js'
integrity='sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa'
crossorigin='anonymous'></script>
<title>Document</title>
{% block CSS %}
{% endblock %}
</head>
<body>
<header class="navbar navbar-inverse">
<!-- 頭部,不允許改變 -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">Nav header</li>
<li><a href="#">Separated link</a></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="../navbar/">Default</a></li>
<li><a href="../navbar-static-top/">Static top</a></li>
<li class="active"><a href="./">Fixed top <span class="sr-only">(current)</span></a></li>
</ul>
</div>
</header>
<main class="container-full">
<div class="row">
<section class="col-sm-3 col-md-2 sidebar">
<!-- 左邊,允許改變一小塊區域 -->
<ul class="nav nav-sidebar">
<li class="active"><a href="#">menu1 <span class="sr-only">(current)</span></a></li>
<li><a href="#">menu2</a></li>
<li><a href="#">menu3</a></li>
<li><a href="#">menu4</a></li>
</ul>
{% block left %}
<!-- 這裡面可以允許修改,相當於給這塊區域起一個名字,left -->
{% endblock %}
</section>
<section class="col-lg-6">
{% block right %}
<!-- 這裡面可以允許修改,相當於給這塊區域起一個名字right -->
{% endblock %}
</section>
</div>
</main>
</body>
{% block Js %}
{% endblock %}
</html>
# 專案根目錄/templats/其他頁面.html
{% extends 'common.html' %}
<!-- 繼承common.html -->
{% block left %}
<!-- 修改內容 -->
<ul class="nav nav-sidebar">
<li><a href="">menu-div-1</a></li>
<li><a href="">menu-div-2</a></li>
<li><a href="">menu-div-3</a></li>
</ul>
{% endblock %}
{% block right %}
<!-- 修改內容 -->
<h4>Subheading</h4>
<p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
<h4>Subheading</h4>
<p>Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras mattis consectetur purus sit amet fermentum.</p>
<h4>Subheading</h4>
<p>Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
{% endblock %}
{% block css %}
<!-- 修改CSS -->
{% endblock %}
{% block js %}
<!-- 修改Js -->
{% endblock %}
模板引入
模板引入是在一個HTML
中引入一段公用的HTML
程式碼。
# 專案根目錄/templats/common.html
<h1>公用咯<h1>
============================
# 專案根目錄/templats/other.html
{include "common.html"} <!-- 將common.html中程式碼全部拿過來 -->