Django之模板層的實(shí)現(xiàn)代碼
在例子視圖中返回文本的方式有點(diǎn)特別,即HTML被直接硬編碼在Python代碼之中。
def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
盡管這種技術(shù)便于解釋視圖是如何工作的,但直接將HTML硬編碼到你的視圖里卻并是一個(gè)好主意。讓我們來看一下為什么:
- 對(duì)頁(yè)面設(shè)計(jì)進(jìn)行的任何改變都必須對(duì)Python代碼進(jìn)行相應(yīng)的修改。站點(diǎn)設(shè)計(jì)的修改往往比底層Python代碼的修改要頻繁得多,因此如果可以在不進(jìn)行Python代碼修改的情況下變更設(shè)計(jì),將會(huì)方便很多。
- Python代碼編寫和HTML設(shè)計(jì)是兩項(xiàng)不同的工作,大多數(shù)專業(yè)的網(wǎng)站開發(fā)環(huán)境都將他們分配給不同的人員(甚至不同的部門)來完成。設(shè)計(jì)者和HTML/CSS的編碼人員不應(yīng)該被要求去編輯Python的代碼來完成他們的工作。
- 程序員編寫Python代碼和設(shè)計(jì)人員制作模板兩項(xiàng)工作過同時(shí)進(jìn)行的額效率是最高的,遠(yuǎn)勝于讓一個(gè)人等待另一個(gè)人完成對(duì)某個(gè)既包含Python又包含HTML的文件的編輯工作。
基于這些原因,將頁(yè)面的設(shè)計(jì)和Python的代碼分離開會(huì)更干凈簡(jiǎn)潔更容易維護(hù)。我們可以使用Django的模板系統(tǒng)(Template System)來是現(xiàn)在這種模式,這就是本章要具體討論的問題。
Python的模板:HTML代碼 + 模板語(yǔ)法
def current_time(req): # ================================原始的視圖函數(shù) # import datetime # now=datetime.datetime.now() # html="<html><body>現(xiàn)在時(shí)刻:<h1>%s.</h1></body></html>" %now # ================================django模板修改的視圖函數(shù) # from django.template import Template,Context # now=datetime.datetime.now() # t=Template('<html><body>現(xiàn)在時(shí)刻是:<h1>{{current_date}}</h1></body></html>') # #t=get_template('current_datetime.html') # c=Context({'current_date':str(now)}) # html=t.render(c) # # return HttpResponse(html) #另一種寫法(推薦) import datetime now=datetime.datetime.now() return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})
一、模板語(yǔ)法之變量
在Django模板中遍歷復(fù)雜數(shù)據(jù)結(jié)構(gòu)的關(guān)鍵是句點(diǎn)字符,語(yǔ)法:
{{var_name}}
views.py:
def index(request): import datetime s="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=name person_yuan=Person("yuan") # 自定義類對(duì)象 person_egon=Person("egon") person_alex=Person("alex") person_list=[person_yuan,person_egon,person_alex] return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})
template:
<h4>{{s}}</h4> <h4>列表:{{ l.0 }}</h4> <h4>列表:{{ l.2 }}</h4> <h4>字典:{{ dic.name }}</h4> <h4>日期:{{ date.year }}</h4> <h4>類對(duì)象列表:{{ person_list.0.name }}</h4> 注:句點(diǎn)符也可以用來引用對(duì)象的方法(無參數(shù)方法): <h4>字典:{{ dic.name.upper }}</h4>
二、模板之過濾器
語(yǔ)法:
{{obj|filter_name:param}}
default
如果一個(gè)變量是False后者為空,使用給定的默認(rèn)值。否則,使用變量的值。例如:
{{ value|default:'nothing' }}
length
返回值的長(zhǎng)度。它對(duì)字符串和列表都起作用。例如:
{{ value|length }}
如果value是 ['a', 'b', 'c', 'd'] ,那么輸出的就是4.
filesizeformat
將值格式化為一個(gè) “人類可讀的” 文件尺寸 (例如 '13 KB' , '4.1 MB' , '102 bytes' , 等等)。例如:
{{ value|filesizeformat }}
如果value = 123456789,輸出將會(huì)是117.7 MB。
date
如果value = datetime.datetime.now()
{{ value|date:"Y-m-d" }}
slice
如果value = "hello world"
{{ value|slice:"2:-1" }}
truncatechars
如果字符串字符多于指定的字符數(shù)量,那么會(huì)被截?cái)?。截?cái)嗟淖址畬⒁钥煞g的省略號(hào)序列("...")結(jié)尾。
參數(shù):要截?cái)嗟淖址麛?shù)
{{ value|truncatechars:9 }}
safe
Django的模板中會(huì)對(duì)HTML標(biāo)簽和JS語(yǔ)法等標(biāo)簽進(jìn)行自動(dòng)轉(zhuǎn)義,原因顯而易見這樣是為了安全。但是有時(shí)候我們可能不希望這些HTML元素被轉(zhuǎn)義,比如我們做一個(gè)內(nèi)容管理系統(tǒng),后他添加的文章中是經(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)義。比如:
value = "<a href=''>點(diǎn)擊</a>" {{ value|safe }}
三、模板之標(biāo)簽
標(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è)元素:
可以利用 {% for obj in list reversed %}
方向完成循環(huán)。
遍歷一個(gè)字典:
{% for key,val in dic.items %} <p>{{ key }}:{{ val }}</p> {% endfor %}
注:循環(huán)序號(hào)可以通過 {{ for|loop }} 顯示
forloop.counter # The current iteration of the loop (1-indexed) forloop.counter0 # The current iteration of the loop (0-indexed) forloop.revcounter # The number of iterations from the end of the loop (1-indexed) forloop.revcounter0 # The number of iterations from the end of the loop (0-indexed) forloop.first # True if this is the first time through the loop forloop.last # True if this is the last time through the loop 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> {% elif num > 80 and num < 100 %} <p>優(yōu)秀</p> {% else %} <p>湊活吧</p> {% endif %}
with 標(biāo)簽
使用一個(gè)簡(jiǎn)單地名字緩存一個(gè)復(fù)雜的變量,當(dāng)你需要使用一個(gè)“昂貴”的方法(比如訪問數(shù)據(jù)庫(kù))很多次的時(shí)候是非常有用的。例如:
{% with total=business.employees.count %} {{ total }} employee{{ total|pluralize }} {% endwith %}
csrf_token 標(biāo)簽
這個(gè)標(biāo)簽用于跨站請(qǐng)求偽造保護(hù)。
四、自定義標(biāo)簽和過濾器
1、在settings中的INSTALLED_APPS配置當(dāng)前app,不然Django無法找到自定義的simple_tag。
2、在app中創(chuàng)建templatetags模塊(模塊名只能是templatetags)。
3、創(chuàng)建任意 .py 文件,如:my_tags.py。
from django import template from django.utils.safestring import mark_safe register = template.Library() #register的名字是固定的,不可改變 @register.filter def filter_multi(v1,v2): return v1 * v2 <br> @register.simple_tag def simple_tag_multi(v1,v2): return v1 * v2 <br> @register.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_multi:2 }} #24 {{ num|filter_multi:"[22,333,4444]" }} {% simple_tag_multi 2 5 %} 參數(shù)不限,但不能放在if for語(yǔ)句中 {% simple_tag_multi num 5 %} 注:filter可以用在if等語(yǔ)句后,simpe_tag不可以。 {% if num|filter_multi:30 > 100 %} {{ num|filter_multi:30 }} {% endif %}
五、模板繼承(extend)
Django模板引擎中最強(qiáng)大也是最復(fù)雜的部分就是模板繼承了。模板繼承可以讓你創(chuàng)建一個(gè)基本的“骨架”模板,它包含你站點(diǎn)中的全部元素,并且可以定義能夠被子模板覆蓋的blocks.
通過從下面這個(gè)例子開始,可以容易地理解模板繼承:
<!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" /> <title>{% block title %}My amazing site{%/span> endblock %}</title> </head> <body> <div id="sidebar"> {% block sidebar %} <ul> <li><a href="/" rel="external nofollow" rel="external nofollow" >Home</a></li> <li><a href="/blog/" rel="external nofollow" rel="external nofollow" >Blog</a></li> </ul> {% endblock %} </div> <div id="content"> {% block content %}{% endblock %} </div> </body> </html>
假設(shè)這個(gè)模板叫做 base.html,它定義了一個(gè)可以用于兩列排版頁(yè)面的簡(jiǎn)單HTML骨架?!白帜0濉钡墓ぷ魇怯盟鼈兊膬?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。
那時(shí),模板引擎將注意到 base.html 中的三個(gè)block標(biāo)簽,并用子模板中的內(nèi)容來替換這些block。根據(jù)blog_entries的值,輸出可能看起來是這樣的:
<!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" /> <title>My amazing blog</title> </head> <body> <div id="sidebar"> <ul> <li><a href="/" rel="external nofollow" rel="external nofollow" >Home</a></li> <li><a href="/blog/" rel="external nofollow" rel="external nofollow" >Blog</a></li> </ul> </div> <div id="content"> <h2>Entry one</h2> <p>This is my first entry.</p> <h2>Entry two</h2> <p>This is my second entry.</p> </div> </body> </html>
請(qǐng)注意,子模版并沒有定義 sidebar block,所以系統(tǒng)使用了父模版中的值。父模版的 {% block %} 標(biāo)簽中的內(nèi)容總是被用作備選內(nèi)容(fallback)。這種方式使代碼得到最大程度的復(fù)用,并且使得添加內(nèi)容到共享的內(nèi)容區(qū)域更加簡(jiǎn)單,例如,部分范圍內(nèi)的導(dǎo)航。
下面是使用繼承的一些提示:
- 如果你在模版中使用 {% extends %} 標(biāo)簽,它必須是模版中的第一個(gè)標(biāo)簽。其他的任何情況下,模版繼承都將無法工作。
- 在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 %} 中。
- If you need to get the content of the block from the parent template, the variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.
為了更好的可讀性,你也可以給你的 {% endblock %} 標(biāo)簽一個(gè) 名字 。例如:
{% block content %} ... {% endblock content %}
在大型模板中,這個(gè)方法幫你清楚地看到哪一個(gè) {% block %} 標(biāo)簽被關(guān)閉了。
不能在一個(gè)模版中定義多個(gè)相同名字的 block 標(biāo)簽。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于OpenCv實(shí)現(xiàn)的人臉識(shí)別(附Python完整代碼)
人臉識(shí)別是基于人的臉部特征信息進(jìn)行身份識(shí)別的一種生物識(shí)別技術(shù),下面這篇文章主要給大家介紹了關(guān)于如何基于OpenCv實(shí)現(xiàn)的人臉識(shí)別,文中還附Python完整代碼,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11Python基礎(chǔ)請(qǐng)求庫(kù)urllib模塊使用深入探究
在Python中,urllib庫(kù)是一個(gè)強(qiáng)大的模塊,用于處理URLs,它包含了多個(gè)子模塊,其中urllib.request是用于發(fā)出HTTP請(qǐng)求的核心組件,本文將深入探討urllib的基本使用、高級(jí)功能以及一些實(shí)際場(chǎng)景的示例,方便更全面地了解這個(gè)重要的網(wǎng)絡(luò)請(qǐng)求工具2024-01-01Python+OpenCV檢測(cè)燈光亮點(diǎn)的實(shí)現(xiàn)方法
這篇文章主要介紹了Python+OpenCV檢測(cè)燈光亮點(diǎn)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11使用OpenCV-python3實(shí)現(xiàn)滑動(dòng)條更新圖像的Canny邊緣檢測(cè)功能
這篇文章主要介紹了使用OpenCV-python3實(shí)現(xiàn)滑動(dòng)條更新圖像的Canny邊緣檢測(cè)功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12python取均勻不重復(fù)的隨機(jī)數(shù)方式
今天小編就為大家分享一篇python取均勻不重復(fù)的隨機(jī)數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11淺談matplotlib默認(rèn)字體設(shè)置探索
這篇文章主要介紹了matplotlib默認(rèn)字體設(shè)置探索,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02