Django_render 模板語法 模板引擎是一種可以讓開發者把服務端數據填充到html網頁中完成渲染效果的技術。它實現了把前端代碼和服務端代碼分離的作用,讓項目中的業務邏輯代碼和數據表現代碼分離,讓前端開發者和服務端開發者可以更好的完成協同開發。 靜態網頁:頁面上的數據都是寫死的,萬年不變 動態 ...
Django_render
模板語法
模板引擎是一種可以讓開發者把服務端數據填充到html網頁中完成渲染效果的技術。它實現了把前端代碼和服務端代碼分離的作用,讓項目中的業務邏輯代碼和數據表現代碼分離,讓前端開發者和服務端開發者可以更好的完成協同開發。
靜態網頁:頁面上的數據都是寫死的,萬年不變
動態網頁:頁面上的數據是從後端動態獲取的(比如後端獲取當前時間;後端獲取資料庫數據然後傳遞給前端頁面)
Django框架中內置了web開發領域非常出名的一個DjangoTemplate模板引擎(DTL)。DTL官方文檔
要在django框架中使用模板引擎把視圖中的數據更好的展示給客戶端,需要完成3個步驟:
在項目配置文件中指定保存模板文件的模板目錄。一般模板目錄都是設置在項目根目錄或者主應用目錄下。
在視圖中基於django提供的渲染函數綁定模板文件和需要展示的數據變數
在模板目錄下創建對應的模板文件,並根據模板引擎內置的模板語法,填寫輸出視圖傳遞過來的數據。
配置模板目錄:在當前項目根目錄下創建了模板目錄templates. 然後在settings.py, 模板相關配置,找到TEMPLATES配置項,填寫DIRS設置模板目錄。
render內部本質
def index(request):
name = "hello world!"
# 1. 初始化模板,讀取模板內容,實例化模板對象
# get_template會從項目配置中找到模板目錄,我們需要填寫的參數就是補全模板文件的路徑
template = get_template("index.html")
# 2. 識別context內容, 和模板內容裡面的標記[標簽]替換,針對複雜的內容,進行正則的替換
context = {"name": name}
content = template.render(context, request) # render中完成了變數替換成變數值的過程,這個過程使用了正則。
print(content)
# 3. 通過response響應對象,把替換了數據的模板內容返回給客戶端
return HttpResponse(content)
# 上面代碼的簡寫,直接使用 django.shortcuts.render
# return render(request, "index.html",context={"name":name})
# return render(request,"index3.html", locals())
# data = {}
# data["name"] = "xiaoming"
# data["message"] = "你好!"
# return render(request,"index3.html", data)
- DTL模板文件與普通html文件的區別在哪裡?
DTL模板文件是一種帶有特殊語法的HTML文件,這個HTML文件可以被Django編譯,可以傳遞參數進去,實現數據動態化。在編譯完成後,生成一個普通的HTML文件,然後發送給客戶端。
- 開發中,我們一般把開發中的文件分2種,分別是靜態文件和動態文件。
- 靜態文件,數據保存在當前文件,不需要經過任何處理就可以展示出去。普通html文件,圖片,視頻,音頻等這一類文件叫靜態文件。
- 動態文件,數據並不在當前文件,而是要經過服務端或其他程式進行編譯轉換才可以展示出去。 編譯轉換的過程往往就是使用正則或其他技術把文件內部具有特殊格式的變數轉換成真實數據。 動態文件,一般數據會保存在第三方存儲設備,如資料庫中。django的模板文件,就屬於動態文件。
模板語法內容
變數渲染(深度查詢、過濾器)
{{val}} {{val|filter_name:參數}}
標簽
{% tag_name %}
嵌套和繼承
1.1 深度查詢
def index(request):
name = "ZhangJR"
age = 22
is_married = True
course = ["global education","hongkong economy"]
regina = {
"name":"ZhangJR",
"age": 22,
"is_married": True,
}
class info():
def __init__(self,name,age):
self.name = name
self.age = age
Info = info("ZhangJR",22)
Info1 = info("ZhangJR",22)
Info2 = info("regina", 23)
Info3 = info("ivnalee", 24)
Info4 = info("qianniu", 25)
Infos = [Info1,Info2,Info3,Info4]
return render(request,"index.html",locals())
深度查詢在查詢屬性或者取值的過程都用
.
作為判斷,locals函數代表將視圖函數所有的內容全部傳送給模板文件渲染分別通過普通類型,字典類型,類,類的列表進行學習
<h3>深度查詢:句點符"."</h3>
<hr>普通類型
<p>姓名:{{name}}</p>
<p>年齡:{{age}}</p>
<p>婚否:{{is_married}}</p>
<p>課程:{{course}}</p>
<p>第一個課程:{{course.0}}</p>
<hr>字典
<p>個人信息:{{regina}}</p>
<p>個人名字:{{regina.name}}</p>
<p>個人年齡:{{regina.age}}</p>
<hr>類對象
<p>類對象名字:{{Info.name}}</p>
<p>類對象年齡:{{Info.age}}</p>
<hr>類列表取值
<p>第二個人的姓名:{{Infos.1.name}}</p>
1.2 內置過濾器
語法:
{{obj|過濾器名稱:過濾器參數}}
內置過濾器
過濾器 | 用法 | 代碼 |
---|---|---|
last | 獲取列表/元組的最後一個成員 | {{list | last}} |
first | 獲取列表/元組的第一個成員 | {{list|first}} |
length | 獲取數據的長度 | {{list | length}} |
default | 當變數沒有值的情況下, 系統輸出預設值, | {{str|default:"預設值"}} |
safe | 讓系統不要對內容中的html代碼進行實體轉義 | {{htmlcontent| safe}} |
upper | 字母轉換成大寫 | {{str | upper}} |
lower | 字母轉換成小寫 | {{str | lower}} |
title | 每個單詞首字母轉換成大寫 | {{str | title}} |
date | 日期時間格式轉換 | `{{ value |
cut | 從內容中截取掉同樣字元的內容 | {{content | cut:"hello"}} |
list | 把內容轉換成列表格式 | {{content | list}} |
add | 加法 | {{num| add}} |
filesizeformat | 把文件大小的數值轉換成單位表示 | {{filesize | filesizeformat}} |
join |
按指定字元拼接內容 | {{list| join("-")}} |
random |
隨機提取某個成員 | {list | random}} |
slice |
按切片提取成員 | {{list | slice:":-2"}} |
truncatechars |
按字元長度截取內容 | {{content | truncatechars:30}} |
truncatewords |
按單詞長度截取內容 | 同上 |
Infos = [Info1.name,Info2.name,Info3.name,Info4.name]
<p>信息的最後一個人的姓名:{{Infos | last}}</p>
<p>信息的第一個人的姓名:{{Infos | first}}</p>
<p>共有{{Infos | length}}個人</p>
-
預設值
如果渲染的值為空,可以添加預設渲染值,效果如圖
Name= "" 姓名{{Name}}
如果變成<p>姓名 {{Name|default:"regina"}}</p>
(default後面不能有空格)
-
日期轉換
now = datetime.datetime.now() <p>當前時間預設格式:{{now}}</p> <p>格式化日期:{{now|date:"Y-m-d"}}</p> <p>格式化日期2:{{now|date:"D/d/m/Y"}}</p>
-
文件大小
filesizeformat
過濾器自動會識別位元組大小進行單位的選擇file1 = 717 file2 = 127717 file3 = 1271221 file4 = 1155178797 <p>文件大小:{{file1|filesizeformat}}</p> <p>文件大小:{{file2|filesizeformat}}</p> <p>文件大小:{{file3|filesizeformat}}</p> <p>文件大小:{{file4|filesizeformat}}</p>
-
按字元截斷
str = "ABCDEFGHIJK" <p>content: {{str | truncatechars:6}}</p>
這個...預設算作了一個字元
-
safe過濾
如果我們輸入的是一段帶有標簽的html語言,類似於
link = "<a href='www.gs.cuhk.edu.hk'>cuhk</a>" script = "<script>alert('regina')</script>"
如果正常傳輸,那網頁上得到的則是
並不是一個我們想要的效果,因為預設過濾器會對一些字元進行轉義,打開頁面源碼就會發現這一問題
如果我們加上safe過濾器
<p>link:{{link| safe}}</p> <p>script:{{script|safe}}</p>
代碼也沒有進行任何的修改
1.3 自定義過濾器
雖然官方已經提供了許多內置的過濾器給開發者,但是很明顯,還是會有存在不足的時候。例如:希望輸出用戶的手機號碼時, 13912345678 ---->> 139*****678
,這時我們就需要自定義過濾器。要聲明自定義過濾器並且能在模板中正常使用,需要完成2個前置的工作:
當前使用和聲明過濾器的子應用必須在setting.py配置文件中的INSTALLED_APPS中註冊了!!!
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
這裡面並沒有添加自定義的app進去,現在我們找到如下文件,併在上述代碼添加
regina.apps.ReginaConfig
自定義過濾器函數必須被 template.register進行裝飾使用,而且過濾器函數所在的模塊必須在templatetags包裡面保存
在home子應用下創建templatetags包[必須包含
__init__.py
], 在包目錄下創建任意py文件myfilters的名字是自定義的,這裡就是存儲過濾函數,並需要在最開始加上一些頭文件
from django import template register = template.Library() @register.filter("mobile") def mobile(number): return number[:3]+"****"+number[-3:]
在需要使用的模板文件中頂部使用load標簽載入過濾器文件my_filters.py並調用自定義過濾器
{% load myfilters %}
過濾的函數要和myfilters文件裡面的函數是同名的
最終當輸入一個手機號時,得到就是一個隱藏後的手機號
2.1 標簽
{% tagname %}
if標簽
is_married = True
{% if is_married == True %}
<p>張女士已婚</p>
{% else %}
<p>張女士未婚</p>
{% endif %}
這裡需要註意的幾個點:
- {% if condition %}這裡的condition和if都需要和周圍的%空開一格
- {% if is_married == true %}這裡要用雙等號
- 最後一定要加{% endif %}
<div>
{% if age < 20 %}
<p>太小</p>
{% elif age < 22 %}
<p>還行</p>
{% else %}
<p>正好</p>
{% endif %}
</div>
for迴圈
<ul>
{% for name in course %}
<li>{{ name }}</li>
{% endfor %}
</ul>
<table width="800" border="1" align="center">
<tr>
<th>序號</th>
<th>姓名</th>
<th>年齡</th>
</tr>
{% for info in Infos %}
<tr align="center">
<td>{{ forloop.counter }}</td>
<td>{{ info.name }}</td>
<td>{{ info.age }}</td>
</tr>
{% endfor %}
</table>
還可以結合if判斷
{% for info in Infos %}
{% if forloop.first %}
<tr align="center" class="pink">
<td>{{ forloop.counter }}</td>
<td>{{ info.name }}</td>
<td>{{ info.age }}</td>
</tr>
{% else %}
<tr align="center">
<td>{{ forloop.counter }}</td>
<td>{{ info.name }}</td>
<td>{{ info.age }}</td>
</tr>
{% endif %}
{% endfor %}
或者還可以
{% elif info.age > 23 %}
<tr align="center" >
<td>{{ forloop.counter }}</td>
<td class="blue">{{ info.name }}</td>
<td>{{ info.age }}</td>
</tr>
迴圈中, 模板引擎提供的forloop對象,用於給開發者獲取迴圈次數或者判斷迴圈過程的.
屬性 | 描述 |
---|---|
forloop.counter | 顯示迴圈的次數,從1開始 |
forloop.counter0 | 顯示迴圈的次數,從0開始 |
forloop.revcounter0 | 倒數顯示迴圈的次數,從0開始 |
forloop.revcounter | 倒數顯示迴圈的次數,從1開始 |
forloop.first | 判斷如果本次是迴圈的第一次,則結果為True |
forloop.last | 判斷如果本次是迴圈的最後一次,則結果為True |
forloop.parentloop | 在嵌套迴圈中,指向當前迴圈的上級迴圈 |
3 嵌套繼承
傳統的模板分離技術,依靠{% include "模板文件名"%}實現,這種方式,雖然達到了頁面代碼復用的效果,但是由此也會帶來大量的碎片化模板,導致維護模板的成本上升.因此, Django框架中除了提供這種模板分離技術以外,還並行的提供了 模板繼承給開發者.
{% include "模板文件名"%} # 模板嵌入
{% extends "base.html" %} # 模板繼承
3.1 include
假設現在有兩個頁面公用一個同樣式的東西,即頁面底部有一個廣告~
在每一個頁面里都添加一句
{% include "same.html" %}
此時兩個頁面就同時擁有了這一元素
3.2 extends繼承
因為一個頁面繼承的東西可能有很多,而且有很多的固定框架,不可能每一個都用include進行繼承,此時就需要extends關鍵字,首先我們來用bootstrap學習一下,然後在我們需要自己渲染的位置上添加區塊
<div class="col-md-10">
<div class="theme-showcase" role="main">
{% block content %}
<p>hello world!</p>
{% endblock %}
</div>
</div>
其中content是自定義的名字,在模板文件里也同樣要用這個名字,然後在其他文件里進行導入這個文件
{% extends "same.html" %}
.....
{% block content %}
原來渲染的內容
{% endblock %}
被extends的文件在未使用時是這樣的
我們看到有兩個塊是要傳遞給模板文件渲染的,index.html
和test.html
同時繼承了這一文件,效果如圖
- 如果你在模版中使用
{% extends %}
標簽,它必須是模版中的第一個標簽。其他的任何情況下,模版繼承都將無法工作。- 在base模版中設置越多的
{% block %}
標簽越好。請記住,子模版不必定義全部父模版中的blocks,所以,你可以在大多數blocks中填充合理的預設內容,然後,只定義你需要的那一個。多一點鉤子總比少一點好。- 為了更好的可讀性,你也可以給你的
{% endblock %}
標簽一個 名字 。例如:{``%
block content``%``}``...``{``%
endblock content``%``},
在大型模版中,這個方法幫你清楚的看到哪一個{% block %}
標簽被關閉了。- 不能在一個模版中定義多個相同名字的
block
標簽。
在最開始的same頁面中,我們是添加了一句話的,雖然這句話並不重要,但是如果我們繼承的時候也想要這句話,就需要把語句改為
{% block content %}
{{ block.super }}
....
此時原來same.html
裡面的block內容也可以得到繼承
本文來自博客園,作者:ivanlee717,轉載請註明原文鏈接:https://www.cnblogs.com/ivanlee717/p/16695109.html