一、Django模板
二、常用操作
兩種特殊符號: {{ }} 和 {% %}
變量相關的用: {{ }}
邏輯相關的用: {% %}
2.1 變量
在Django的模板語言中按此語法使用:{{ 變量名 }}
當模版引擎遇到一個變量,它將計算這個變量,然后用結果替換掉它本身;變量的命名包括任何字母數字以及下划線 _ 的組合,變量名稱中不能有空格或標點符號。
點 . 在模板語言中有特殊的含義。當模版系統遇到點,它將以這樣的順序查詢:
- 字典查詢(Dictionary lookup)
- 屬性或方法查詢(Attribute or method lookup)
- 數字索引查詢(Numeric index lookup)
示例:
# views.py中
class Person(): def __init__(self, name, age): self.name = name self.age = age def sleep(self): return "{}正在睡覺...".format(self.name) def template_test(request): p1 = Person("野豬佩奇", 1) p2 = Person("三毛", 2) p_list = [p1, p2] lst = [10, "Zz", 20, "Ss"] dct = {"name": "pd", "age": 18, "hobby": "swimming"} return render(request, "template_test.html", {"p_list": p_list, "lst": lst, "dct": dct})
模板中支持的寫法:
{# 取lst中第一個參數 #} {{ lst.0 }} # 10 {# 取字典中key的值 #} {{ dct.hobby }} # swimming {# 取對象的name屬性 #} {{ p_list.1.name }} # 三毛 {# .操作只能調用不帶參數的方法 #} {{ p_list.0.sleep }} # 野豬佩奇正在睡覺...
2.2 Filters(過濾器)
在Django的模板語言中,通過使用過濾器來改變變量的顯示。
語法:{{ value|filter_name:參數 }}
例如:上面例子有個這樣寫 {{ dct.hobby|upper }} 會將 dct.hobby 變量應用 upper 過濾器之后再顯示它的值;顯示結果為 SWIMMING
注意:
- 過濾器支持"鏈式"操作;即一個過濾器的輸出作為另一個過濾器的輸入
- 過濾器可以接受參數,例如:{{ sss|truncatewords:20 }},這將顯示sss的前20個詞
- 過濾器參數包含空格的話,必須用引號包裹起來;比如使用逗號和空格去連接一個列表中的元素,如:{{ list|join:', ' }}
- 管道符 | 左右沒有空格!!!
一些Django的模板語言中的內置過濾器如下:
default
如果一個變量是false或者為空,使用給定的默認值;否則,使用變量的值。
{{ value|default:"xx" }} # 如果value沒有傳值或者值為空的話就顯示xx
length
返回值的長度,作用於字符串和列表。
{{ value|length }} # 返回value的長度,如 value=[10, "Zz", 20, "Ss"] 的話,就顯示4
filesizeformat
將值格式化為 10kb 10MB 10bytes 等等
{{ value|filesizeformat }}
# 如果value=12345678,輸出將會是 11.8 MB。
slice
切片,顧頭不顧尾,不能反着切,如 "-2:2"
{{ value|slice:"2:-2" }}
# 如果value="12345678",輸出為3456
date
格式化
{{ value|date:"Y-m-d H:i:s"}}
示例:
# views.py文件中 from datetime import datetime def template_test(request): time = datetime.now() return render(request, "template_test.html", {"time": time})
{{ time|date:"Y-m-d H:i:s"}} # 輸出為2018-10-29 17:51:11
可用的參數:
格式化字符 | 描述 | 示例輸出 |
---|---|---|
a | "a.m." 或"p.m." (請注意,這與PHP的輸出略有不同,因為這包括符合Associated Press風格的期間) |
"a.m." |
A | "AM" 或"PM" 。 |
"AM" |
b | 月,文字,3個字母,小寫。 | "jan" |
B | 未實現。 | |
c | ISO 8601格式。 (注意:與其他格式化程序不同,例如“Z”,“O”或“r”,如果值為naive datetime,則“c”格式化程序不會添加時區偏移量(請參閱datetime.tzinfo ) 。 |
2008-01-02T10:30:00.000123+02:00 或2008-01-02T10:30:00.000123 如果datetime是天真的 |
d | 月的日子,帶前導零的2位數字。 | "01" 到"31" |
D | 一周中的文字,3個字母。 | “星期五” |
e | 時區名稱 可能是任何格式,或者可能返回一個空字符串,具體取決於datetime。 | "" 、"GMT" 、"-500" 、"US/Eastern" 等 |
E | 月份,特定地區的替代表示通常用於長日期表示。 | "listopada" (對於波蘭語區域,而不是"Listopad" ) |
f | 時間,在12小時的小時和分鍾內,如果它們為零,則分鍾停留。 專有擴展。 | "1" ,"1:30" |
F | 月,文,長。 | "一月" |
g | 小時,12小時格式,無前導零。 | "1" 到"12" |
G | 小時,24小時格式,無前導零。 | "0" 到"23" |
h | 小時,12小時格式。 | "01" 到"12" |
H | 小時,24小時格式。 | "00" 到"23" |
i | 分鍾。 | "00" 到"59" |
I | 夏令時間,無論是否生效。 | "1" 或"0" |
j | 沒有前導零的月份的日子。 | "1" 到"31" |
l | 星期幾,文字長。 | "星期五" |
L | 布爾值是否是一個閏年。 | True 或False |
m | 月,2位數字帶前導零。 | "01" 到"12" |
M | 月,文字,3個字母。 | “揚” |
n | 月無前導零。 | "1" 到"12" |
N | 美聯社風格的月份縮寫。 專有擴展。 | "Jan." ,"Feb." ,"March" ,"May" |
o | ISO-8601周編號,對應於使用閏年的ISO-8601周數(W)。 對於更常見的年份格式,請參見Y。 | "1999年" |
O | 與格林威治時間的差異在幾小時內。 | "+0200" |
P | 時間為12小時,分鍾和"a.m。"/"p.m。",如果為零,分鍾停留,特殊情況下的字符串“午夜”和“中午”。 專有擴展。 | "1 am" ,"1:30 pm" / t3>, |
r | RFC 5322格式化日期。 | "Thu, 21 Dec 2000 16:01:07 +0200" |
s | 秒,帶前導零的2位數字。 | "00" 到"59" |
S | 一個月的英文序數后綴,2個字符。 | "st" ,"nd" ,"rd" 或"th" |
t | 給定月份的天數。 | 28 to 31 |
T | 本機的時區。 | "EST" ,"MDT" |
u | 微秒。 | 000000 to 999999 |
U | 自Unix Epoch以來的二分之一(1970年1月1日00:00:00 UTC)。 | |
w | 星期幾,數字無前導零。 | "0" (星期日)至"6" (星期六) |
W | ISO-8601周數,周數從星期一開始。 | 1 ,53 |
y | 年份,2位數字。 | "99" |
Y | 年,4位數。 | "1999年" |
z | 一年中的日子 | 0 到365 |
Z | 時區偏移量,單位為秒。 UTC以西時區的偏移量總是為負數,對於UTC以東時,它們總是為正。 | -43200 到43200 |
safe
Django的模板中會對HTML標簽和JS等語法標簽進行自動轉義,原因顯而易見,這樣是為了安全。在Django中關閉HTML的自動轉義有兩種方式,如果是一個單獨的變量我們可以通過 過濾器|safe 的方式告訴Django這段代碼是安全的不必轉義。
# 比如 value="<a href='#'>點我</a>" {{ value|safe }} --> 點我 {{ value }} --> <a href='#'>點我</a>
truncatechars
如果字符串字符多於指定的字符數量,那么會被截斷。截斷的字符串將以可翻譯的省略號序列 ... 結尾。
參數:截斷的字符數
{{ value|truncatechars:6 }} # 比如 value="在干嘛,你是誰?",結果為 在干嘛... # ...占了3位
cut
移除value中所有的與給出的變量相同的字符串
{{ value|cut:' ' }} # 如果value='i love you',那么將輸出 iloveyou
join
使用字符串連接列表
{{ value|join:"+" }} # 如果value=[1, 2, 3, 4],輸出為 1+2+3+4
自定義過濾器
自定義過濾器只是帶有一個或兩個參數的Python函數:
- 變量(輸入)的值:不一定是一個字符串
- 參數的值 - 這可以有一個默認值,或完全省略
例如,在過濾器 {{ var|foo:"bar" }} 中,過濾器 foo 將傳遞變量 var 和參數 "bar"
自定義過濾器步驟:
①在 app 目錄下新建一個類型為 Python Package 的 templatetags 文件夾;
②在 templatetags 下創建一個py文件,比如 myfilter.py;
③在 myfilter.py 文件里編寫自定義過濾器,如下:
# myfilter.py文件里 from django import template register = template.Library() @register.filter(name="addname") # 起一個名字 def add_something(value): return "{},去打球嗎?".format(value) @register.filter(name="rename") def re_something(value, arg): return value.replace(arg, "美女")
④使用自定義過濾器
{# 先導入自己定義的filter的那個py文件 #} {% load myfilter %} {# 使用自己定義的過濾器 #} {{ name|addname }} # name = "佩奇" --> 佩奇,去打球嗎? {{ hello|rename:"帥哥" }} # hello = "帥哥,在干嘛?" --> 美女,在干嘛?
Tags(標簽使用)
for...
<ul> {% for user in user_list %} <li>{{ user.name }}</li> {% endfor %} </ul>
for循環可用的一些參數:
for...empty...
<ul> {% for user in user_list %} <li>{{ user.name }}</li> {% empty %} <li>空空如也</li> {% endfor %} </ul>
if...elif...else...
{% if user_list %} 用戶人數:{{ user_list|length }} {% elif black_list %} 黑名單數:{{ black_list|length }} {% else %} 沒有用戶 {% endif %}
if...else...
{% if user_list|length >= 20 %} <p>沒位置、坐不下啦!</p> {% else %} <p>快上車!</p> {% endif %}
if 語句支持 and、or、==、!=、>、>=、<、<=、in、not in、is、is not 判斷
with
當一個語句太長時,定義一個中間變量代替它
# lst = ["佩奇", ["a", {"name": "pd", "age": 18}], 1] {% with age=lst.1.1.age %} {{ age }} # 18 {% endwith %}
注釋
{# ... #}
注意事項
Django的模板語言中屬性的優先級大於方法
def xx(request):
d = {"a": 1, "b": 2, "items": "3"}
return render(request, "xx.html", {"data": d})
如上,在使用render渲染一個頁面的時候,傳的字典d有一個key的名字叫做 items,但是我們知道字典默認有 d.items() 方法,所以在模板語言中:
{{ data.items }}
默認會取字典d中key名字叫做 items 的值,即 3,而不是取字典全部的值!
2.3 模板繼承
假設一個基礎的模板作為母版,如下:
<!DOCTYPE html> <html lang="zh-cn"> <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>{% block title %}<!-- 子頁面的標題 -->{% endblock %}</title> {% block page-css %} <!-- 子頁面傳過來的CSS文件... --> {% endblock %} </head> <body> {% block page-main %} <!-- 子頁面要傳的內容... --> {% endblock %} <!-- 母版自己的內容等等... --> {% block page-js %} <!-- 子頁面傳過來的JS文件... --> {% endblock %} </body> </html>
母版會有其他子頁面相同的內容,當一個子頁面繼承母版時,在相應位置"填充"內容即可,像子頁面的標題、內容、CSS文件、JS文件;一般不會在母版寫子頁面的CSS、JS文件,因為如果有太多子頁面繼承母版,那么會有一個子頁面沒有用到另一個子頁面的CSS、JS文件,就沒有必要導入進來了。
如何繼承母版
首先假設母版的html文件為 base.html、子頁面html文件為 son.html
子頁面繼承母版,想使用母版的頁面,那么在子頁面(son.html)的最上方使用下面的語法即可:
{% extends "base.html" %} 有雙引號!!!
搞定上面這一步,接着使用語法 {% block xxx %} 分別在母版和子頁面定義"塊",比如:
①母版中:
<!DOCTYPE html> <html lang="zh-cn"> <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>{% block title %}{% endblock %}</title> {% block page-css %}{% endblock %} </head> <body> <h1>我是母版的h1標簽</h1> {% block page-son %}{% endblock %} {% block page-js %}{% endblock %} </body> </html>
②子頁面中:
{% extends "base.html" %} {% block title %} 我是子頁面的標題 {% endblock %} {% block page-css %} <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/font-awesome/css/font-awesome.min.css"> <style> h1{ color: red; } </style> {% endblock %} {% block page-son %} <h2>我是子頁面的h2標簽</h2> {% endblock %} {% block page-js %} <script type="text/javascript" src="/static/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="/static/bootstrap/js/bootstrap.js"></script> {% endblock %}
views.py文件中,返回的是子頁面,不是母版!!!
③下面我們來看子頁面是怎么樣的:
很明顯,子頁面中,一個個"塊"傳到了母版對應的"塊"中,最終組成了一個新的子頁面,這就是模板繼承,強大吧!!!
2.4 組件
可以將常用的頁面內容如導航條,頁尾信息等組件保存在單獨的文件中,然后在需要使用的地方按如下語法導入即可。
# 寫對應的html文件,然后在另一個html文件中的某個位置使用語法
{% include "ele.html" %}
比如給剛才上面那個 base.html 母版增加一個導航欄:
直接在 h1 標簽上方寫 {% include "navbar.html" %},這個 navbar.html 可以是完整的html頁面,也可以是單獨的一大塊標簽組成的模塊(比如導航欄),只要能傳到想要展示的頁面且確保能被渲染成功就行。
2.5 靜態文件相關
靜態文件(CSS、JS、圖片等)
{% load static %} <img src="{% static "images/test.jpg" %}"> <link rel="stylesheet" href="{% static "bootstrap/css/bootstrap.min.css" %}"> <script type="text/javascript" src="{% static "jquery-3.3.1.min.js" %}"></script>
當某個文件在同一個 html 文件中多處被用到時,可以存為一個變量,這樣會方便些:
{% load static %} {% static "images/test.jpg" as t1 %}">
<img src="{{ t1 }}"></img> ... <img src="{{ t1 }}"></img>
{% load static %} 這種方法是防止靜態文件寫死,怎么說呢?Django下,靜態文件都放在了 static 目錄下,假如有一天 settings.py 文件中 STATIC_URL = '/static/' 中的 static 被改成了 static666,那么采用 {% load static %} 這種方式導入的靜態文件不受影響,因為這種方法Django會幫我們拼接路徑;但是很少有人會改這個文件,知道有這種方法就好。
三、自定義模板標簽
標簽比過濾器更復雜,因為標簽可以做任何事情。
simple_tag (簡單標簽)
和自定義過濾器類似,但 simple_tag 函數可以接受任意數量的位置或關鍵字參數。
示例:
# app下的 templatetags/my_simple_tag.py 文件中 from django import template register = template.Library() import datetime # 如果不起別名就用函數名,即不用("name="xxx")的話,在html模板中直接用函數名就可以了 @register.simple_tag(name="xxx") def current_time(format_string): return datetime.datetime.now().strftime(format_string) @register.simple_tag def plus(a, b, c): aa = a bb = b cc = c return aa+bb+cc
怎么使用???
在 html 模板中導入自己定義的那個py文件,寫的函數就是自定義模板,如下:
①可以將標記結果存儲在模板變量中,而不是直接輸出它。這是通過使用as
參數后跟變量名來完成的。這樣做可以在自己認為合適的地方輸出內容。
{% load my_simple_tag %} {% xxx "%Y-%m-%d %H:%M:%S" as t%} <h1>北京時間:{{ t }}</h1> # 在瀏覽器中輸出 --> 北京時間:2018-10-30 20:10:09
② simple_tag 函數可以接受任意數量的位置或關鍵字參數。
{% load my_simple_tag %} {% plus 11 22 33 %} # 66 {% plus "11" "22" "33" %} #112233
inclusion_tag (包含標簽)
另一種常見類型的模板標記是通過呈現另一個模板來顯示某些數據的類型。例如,Django的管理界面使用自定義模板標簽顯示"添加/更改"表單頁面底部的按鈕。這些按鈕看起來總是一樣,但鏈接目標會根據正在編輯的對象而改變 - 因此它們是使用填充了當前對象詳細信息的小模板的完美案例。
示例:
# app下的 templatetags/my_inclusion_tag.py 文件中 from django import template register = template.Library() @register.inclusion_tag("inclusion.html") def show_results(n): n = 1 if n < 1 else int(n) data = ["第{}項".format(i) for i in range(1, n+1)] return {"data": data}
這個 inclusion.html 只是用來存放 html 代碼片段,最終是其他 html 拿到這個片段內容展示出來
然后在另一個 html 文件中使用這個自定義包含標簽
# tags.html 文件中 {% load my_inclusion_tag %} # 導入 {% show_results 5 %} # 使用包含標簽,參數為5
那么 tags.html 在瀏覽器中輸出的內容如下:
更多更高級自定義模板標簽在上面給出的鏈接里,由於時間原因,日后再了解。