控制當前的自動轉義行爲。這個標記能夠做爲參數打開或關閉,它決定自動轉義是否在塊內有效。塊使用endautoescape結束標記關閉。
當自動轉義生效時,全部變量內容在將結果放入輸出以前(可是在應用了任何過濾器以後)都要對其應用HTML轉義。這至關於手動將轉義過濾器應用到每一個變量。
惟一的例外是那些已經被標記爲「安全」的變量,它們不會被轉義,或者被填充變量的代碼轉義,或者由於它已經應用了安全或轉義過濾器。javascript
# 轉義,顯示普通字符串,不會解析成html標籤 {% autoescape on %} {{ body }} {% endautoescape %} # 不轉以,解析成html標籤 {% autoescape off %} {{ body }} {% endautoescape %}
定義了一個子模塊能夠繼承的塊html
忽略comment之間的內容,在註釋用於記錄爲何禁用代碼的代碼時,這頗有用。java
此標記用於CSRF保護,防止跨站點僞造請求。node
每次遇到此標記時都會生成它的一個參數。第一個論證產生於第一次相遇,第二個論證產生於第二次相遇,以此類推。一旦全部參數都用完了,標記就會循環到第一個參數,並再次生成它。git
# The first iteration produces HTML that refers to class row1, the second to row2, the third to row1 again, and so on for each iteration of the loop. {% for o in some_list %} <tr class="{% cycle 'row1' 'row2' %}"> ... </tr> {% endfor %}
{% for o in some_list %} <tr class="{% cycle rowvalue1 rowvalue2 %}"> ... </tr> {% endfor %}
{% for o in some_list %} <tr class="{% autoescape off %}{% cycle rowvalue1 rowvalue2 %}{% endautoescape %}"> ... </tr> {% endfor %}
{% for o in some_list %} <tr class="{% cycle 'row1' rowvalue2 'row3' %}"> ... </tr> {% endfor %}
<tr> <td class="{% cycle 'row1' 'row2' as rowcolors %}">...</td> <td class="{{ rowcolors }}">...</td> </tr> <tr> <td class="{% cycle rowcolors %}">...</td> <td class="{{ rowcolors }}">...</td> </tr>
若是隻想聲明循環,而不生成第一個值,則能夠添加一個silent關鍵字做爲標記中的最後一個關鍵字。
{% for obj in some_list %}
{% cycle 'row1' 'row2' as rowcolors silent %}
{% include "subtemplate.html" %}
{% endfor %}數據庫
輸出整個調試信息負載,包括當前上下文和導入的模塊。
{% debug %}express
引用母版django
# the app directory dir1/ template.html base2.html my/ base3.html base1.html #In template.html, the following paths would be valid: {% extends "./base2.html" %} {% extends "../base1.html" %} {% extends "./my/base3.html" %}
經過一個或多個過濾器對塊的內容進行編輯。能夠用管道指定多個過濾器,過濾器能夠有參數,就像在變量語法中同樣。
注意,該塊包含過濾器和endfilter標記之間的全部文本。json
# 變小寫 {% filter force_escape|lower %} This text will be HTML-escaped, and will appear in all lowercase. {% endfilter %}
輸出第一個不爲False的參數變量。若是全部傳遞的變量都爲假,則不輸出任何結果。數組
{% firstof var1 var2 var3 %}
若是傳遞的值都爲False,還能夠給一個默認顯示
{% firstof var1 var2 var3 "fallback value" %}
{% autoescape off %} {% firstof var1 var2 var3 "<strong>fallback value</strong>" %} {% endautoescape %}
{% firstof var1 var2|safe var3 "<strong>fallback value</strong>"|safe %}
列表循環
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
字典循環
{% for key, value in data.items %} {{ key }}: {{ value }} {% endfor %}
forloop.counter 從1開始記錄循環索引
forloop.counter0 從0開始記錄循環索引
forloop.revcounter 反轉顯示forloop.counter
forloop.revcounter0 反轉顯示forloop.counter0
forloop.first 是否爲循環的第一次 返回True/False
forloop.last 是否爲訓話你的最後一次 返回True/False
forloop.parentloop 對於循環嵌套,表示當前循環的父循環
for標記能夠採用一個可選的{% empty %}子句,若是給定的數組爲空或找不到,則會顯示其文本:
條件語句
{% if athlete_list %} Number of athletes: {{ athlete_list|length }} {% elif athlete_in_locker_room_list %} Athletes should be out of the locker room soon! {% else %} No athletes. {% endif %}
一種過期的{% id a==b %}的寫法
檢查一個變量自上次循環以後是否發生了改變
<h1>Archive for {{ year }}</h1> {% for date in days %} {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %} <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a> {% endfor %}
在模板中嵌套模板
# 嵌套的模板和當前模板使用同一個上下文 {% include "demo.html" %}
加載自定義模板標記集。
{% load somelibrary %} {% load foo bar from somelibrary %}
顯示隨機的「lorem ipsum」拉丁文本。這對於在模板中提供示例數據很是有用
{% lorem [count] [method] [random] %}
count:個數 methnod:w表示單詞,p表示HTML段落,b表示純文本段落(默認爲b) random
經過一個公共屬性從新組合一組類似的對象
grouper – the item that was grouped by (e.g., the string 「India」 or 「Japan」).
list – a list of all items in this group (e.g., a list of all cities with country=’India’).
#模板變量 cities = [ {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'}, {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'}, {'name': 'New York', 'population': '20,000,000', 'country': 'USA'}, {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'}, {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'}, ] # 調用regroup方法 {% regroup cities by country as country_list %} <ul> {% for country in country_list %} <li>{{ country.grouper } <ul> {% for city in country.list %} <li>{{ city.name }}: {{ city.population }}</li> {% endfor %} </ul> </li> {% endfor %} </ul> # display India Mumbai: 19,000,000 Calcutta: 15,000,000 USA New York: 20,000,000 Chicago: 7,000,000 Japan Tokyo: 33,000,000 # 調用方法二 {% regroup cities by country as country_list %} <ul> {% for country, local_cities in country_list %} <li>{{ country }} <ul> {% for city in local_cities %} <li>{{ city.name }}: {{ city.population }}</li> {% endfor %} </ul> </li> {% endfor %} </ul>
注:regroup不會對輸入進行排序,若是輸入的列表不是按需求字段排序好的,nameregroup將會把它們顯示爲不一樣的列。
這個問題最簡單的解決方案是在視圖代碼中確保數據按照您想要顯示的方式排序。
另外一個解決方案是使用dictsort過濾器對模板中的數據進行排序,若是您的數據位於字典列表中
{% regroup cities|dictsort:"country" by country as country_list %}
任何有效的模板查找都是從新組標記的合法分組屬性,包括方法、屬性、字典鍵和列表項。例如,若是「country」字段是具備「description」屬性的類的外鍵,則可使用
{% regroup cities by country.description as country_list %}
或者,若是country是一個有選項的字段,它將有get_FOO_display()方法做爲屬性可用,容許您對顯示字符串進行分組,而不是選擇鍵:
{% regroup cities by get_country_display as country_list %}
從新設置前一個循環,以便在下次遇到第一個項目時從新開始。若是沒有參數,{% resetcycle %}將重置模板中定義的最後一個{% cycle %}。
刪除HTML標記之間的空白。這包括製表符和換行符。不會刪除文本間的空格。
顯示特殊字符
Argument Outputs openblock {% closeblock %} openvariable {{ closevariable }} openbrace { closebrace } opencomment {# closecomment #} {% templatetag openblock %} url 'entry_list' {% templatetag closeblock %}
加載namespace中的路由
<a href="{% url "login" %}">登陸</a>
帶參數
{% url 'some-url-name' arg1=v1 arg2=v2 %}
不直接顯示,保存在變量裏
{% url 'some-url-name' arg arg2 as the_url %} <a href="{{ the_url }}">I'm linking to {{ the_url }}</a>
檢索帶有名稱空間的URL,請指定徹底限定名
{% url 'myapp:view-name' %}
中止模板引擎呈現此塊標記的內容。
一個常見的用法是容許JavaScript模板層與Django的語法發生衝突
{% verbatim %} {{if dying}}Still alive.{{/if}} {% endverbatim %} {% verbatim myblock %} Avoid template rendering via the {% verbatim %}{% endverbatim %} block. {% endverbatim myblock %}
以更簡單的名稱緩存複雜的變量。當訪問屢次「昂貴」的方法(例如,訪問數據庫的方法)時,這很是有用
{% with total=business.employees.count %} {{ total }} employee{{ total|pluralize }} {% endwith %}
能夠同時命名多個變量
{% with alpha=1 beta=2 %}
...
{% endwith %}
加參數值給value
{{ value|add:"2" }}
此篩選器將首先嚐試將兩個值強制轉換爲整數。若是失敗,它將嘗試將這些值相加。這將在某些數據類型(字符串、列表等)上工做,在其餘類型上失敗。若是失敗,結果將是一個空字符串
{{ first|add:second }}
first is [1, 2, 3] and second is [4, 5, 6], then the output will be [1, 2, 3, 4, 5, 6].
addslashes
在引號前加斜槓。例如,用於在CSV中轉義字符串。
{{ value|addslashes }}
If value is "I'm using Django", the output will be "I'm using Django".
將值的首字母大寫,若是不是字母,該過濾無效
將值集中在給定寬度的字段中。
{{ value|center:"15" }}
從給定字符串中刪除全部arg值。
{{ value|cut:" " }}
date
根據給定的格式格式化日期。
{{ value|date:"D d M Y" }}
傳遞的格式能夠是預約義的格式之一DATE_FORMAT、DATETIME_FORMAT、SHORT_DATE_FORMAT或SHORT_DATETIME_FORMAT,或使用上面表中顯示的格式說明符的自定義格式。請注意,預約義格式可能因當前語言環境而異。
{{ value|date:"SHORT_DATE_FORMAT" }}
若是value爲False,則顯示denfalut過濾器的參數值
{{ value|default:"nothing" }}
若是value值爲None,則顯示defalut過濾器的參數值
{{ value|default_if_none:"nothing" }}
獲取字典列表並返回按參數中給定的鍵排序的列表。
value = [ {'name': 'zed', 'age': 19}, {'name': 'amy', 'age': 22}, {'name': 'joe', 'age': 31}, ] {{ value|dictsort:"name" }} #output: [ {'name': 'amy', 'age': 22}, {'name': 'joe', 'age': 31}, {'name': 'zed', 'age': 19}, ]
高級用法:
value = [ {'title': '1984', 'author': {'name': 'George', 'age': 45}}, {'title': 'Timequake', 'author': {'name': 'Kurt', 'age': 75}}, {'title': 'Alice', 'author': {'name': 'Lewis', 'age': 33}}, ] {% for book in books|dictsort:"author.age" %} * {{ book.title }} ({{ book.author.name }}) {% endfor %} # output * Alice (Lewis) * 1984 (George) * Timequake (Kurt)
value=[ ('a', '42'), ('c', 'string'), ('b', 'foo'), ] {{ value|dictsort:0 }} # 0不能寫成"0" # output [ ('a', '42'), ('b', 'foo'), ('c', 'string'), ]
與dictsort排序相反
若是值可被參數整除,則返回True。
{{ value|divisibleby:"3" }} # value=21,return True;value=22,return False
轉義字符串的HTML。具體來講,它使這些替換:
{% autoescape off %} {{ title|escape }} {% endautoescape %}
轉義用於JavaScript字符串的字符。這並不能保證字符串在HTML或JavaScript模板文本中使用時是安全的,可是能夠在使用模板生成JavaScript/JSON時防止語法錯誤。
{{ value|escapejs }}
把數字轉換成字節大小
{{ value|filesizeformat }} # value=123456789,return 117.7 MB
返回列表中的第一個值
{{ value|first }} # value=[1,2,3,4,5],return 1
在不使用參數的狀況下,將浮點數四捨五入到小數點後一位——但前提是要顯示小數部分。
value Template Output 34.23234 {{ value|floatformat }} 34.2 34.00000 {{ value|floatformat }} 34 34.26000 {{ value|floatformat }} 34.3 value Template Output 34.23234 {{ value|floatformat:3 }} 34.232 34.00000 {{ value|floatformat:3 }} 34.000 34.26000 {{ value|floatformat:3 }} value Template Output 34.23234 {{ value|floatformat:"0" }} 34 34.00000 {{ value|floatformat:"0" }} 34 39.56000 {{ value|floatformat:"0" }} 40 value Template Output 34.23234 {{ value|floatformat:"-3" }} 34.232 34.00000 {{ value|floatformat:"-3" }} 34 34.26000 {{ value|floatformat:"-3" }} 34.260
返回數字的後數第幾位的值
{{ "123456789"|get_digit:4 }} #6 {{ 123456789|get_digit:"2" }} #8
將IRI(國際化資源標識符)轉換爲適合包含在URL中的字符串。若是您試圖使用URL中包含非ascii字符的字符串,那麼這是必要的。
在已經經過urlencode篩選器的字符串上使用此篩選器是安全的。
{{ value|iriencode }}
使用字符串鏈接列表,好比Python的string .join(list)
{{ value|join:" // " }} # value=['a','b','c'],return "a // b // c"
安全地將Python對象輸出爲JSON,包裝在<script>標記中,以便與JavaScript一塊兒使用。
參數:<script>標籤的HTML " id "。
{{ value|json_script:"hello-data" }} # output <script id="hello-data" type="application/json">{"hello": "world"}</script> # 至關於javascript代碼 var value = JSON.parse(document.getElementById('hello-data').textContent);
返回列表中的最後一項
{{ value|last }}
返回列表的長度
{{ value|length }}
返回長度是否等於參數
{{ value|length_is:"4" }}
用適當的HTML替換純文本中的換行符;一個換行符變成了HTML換行符(
),一個新行加上一個空行變成了段落換行符(
{{ value|linebreaks }} #If value is Joel\nis a slug, the output will be <p>Joel<br>is a slug</p>.
將純文本中的全部換行符轉換爲HTML換行符(
)。
{{ value|linebreaksbr }}
顯示帶有行號的文本。
{{ value|linenumbers }}
將字符串轉換爲全部小寫字母。
{{ value|lower }}
將value轉換成list
{{ value|make_list }} # value="joel",return ['J','o','e','l']
將電話號碼(可能包含字母)轉換爲它的數值等效項。
輸入不必定是有效的電話號碼。這將愉快地轉換任何字符串。
{{ value|phone2numeric }} # value=800-COLLECT,return 800-2655328
若是值不是1則顯示一個後綴,默認後綴爲s
# 默認後綴s You have {{ num_messages }} message{{ num_messages|pluralize }}. # 自定義後綴 You have {{ num_walruses }} walrus{{ num_walruses|pluralize:"es" }}. # 兩個參數 第一個表示1顯示的後綴 第二個表示非1顯示的後綴 You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}
返回列表中的任意值
{{ value|random }}
左對齊給定寬度字段中的值
{{ value|ljust:"10" }}
右對齊給定寬度字段中的值
{{ value|ljust:"10" }}
將字符串標記爲在輸出以前不須要進一步的HTML轉義。當自動轉義關閉時,此篩選器無效。
{{ var|safe }}
若是您正在連接過濾器,在safe以後應用的過濾器會使內容再次不安全。
將安全過濾器應用於序列的每一個元素。與其餘對序列(如鏈接)進行操做的過濾器一塊兒使用。
{ some_list|safeseq|join:", " }}
返回列表分割的一部分。
{{ some_list|slice:":2" }} # some_list=['a','b','c'],return ['a','b']
根據參數(字符串格式說明符)格式化變量。
{{ value|stringformat:"E" }}
清楚value中的html標籤
{{ value|striptags }}
格式化時間
{{ value|time:"H:i" }} # return "01:23"
將日期格式化爲日期以後的時間(例如,「4天,6小時」)。
{{ blog_date|timesince:comment_date }} # return 兩個時間的時間差
與timesince相似,格式顯示(「4周」)
{{ conference_date|timeuntil:from_date }}
將value按title形式顯示
{{ value|title }}
將value截斷加...顯示
{{ value|truncatechars:9 }}
與truncatechars相似,可接受html字符串,並忽略html標籤 只截斷文本內容
{{ value|truncatechars_html:9 }}
與truncatechars相似,截斷多少個word。
{{ value|truncatewords:2 }} If value is "Joel is a slug", the output will be "Joel is ...".
與truncatewords相似,可接受htnm字符串
遞歸地獲取一個自嵌套列表並返回一個HTML無序列表——不須要打開和關閉
將value值變大寫
{{ value|upper }}
轉義url字符串
{{ value|urlencode }}
將文本中的url或者email地址轉換成能夠點擊的<a>標籤
{{ value|urlize }}
與urlize相似,能夠截斷url字符
{{ value|urlizetrunc:15 }} # value="Check out www.djangoproject.com",return 'Check out <a href="http://www.djangoproject.com" rel="nofollow">www.djangopr...</a>'
返回單詞個數
{{ value|wordcount }} # value="Joel is a slug",return 4
將單詞包裝在指定的行長度
{{ value|wordwrap:5 }}
加載STATIC_ROO到當前template
{% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!">
若是您須要對static_url被注入到模板的確切位置和方式有更多的控制,您可使用get_static_prefix模板標記
{% load static %} <img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!"> {% load static %} {% get_static_prefix as STATIC_PREFIX %} <img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!"> <img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!">
與get_static_prefix相似,get_media_prefix使用媒體前綴MEDIA_URL填充一個模板變量
{% load static %} <body data-media-url="{% get_media_prefix %}">
django模板提供了豐富的標籤和過濾器用來知足應用程序邏輯表示需求。可是有時,這些內置的功能不能知足需求,就能夠經過自定義標記和過濾器來擴展模板引擎,而後再使用{% load %}標記將它們提供給你的模板。
自定義標記和過濾器通常在app內部指定,或者添加在一個新的app中。它們應該存在一個名叫templatetags的包中。
自定義標記和過濾器的名字與模板load的名字相同,應避免與其餘app中的自定義標記和過濾器名字相同。
# the app layout polls/ __init__.py models.py templatetags/ __init__.py poll_extras.py views.py # in your template you would use the following {% load poll_extras %}
包含自定義標記和過濾器的app必須在setting文件的INSTALLED_APPS中,
要成爲有效的標記庫,模塊必須包含一個名爲register的模塊級變量,該變量是一個模板。庫實例,其中註冊了全部標記和過濾器。
from django import template register = template.Library()
您須要經過一個django.template.Library實例來註冊過濾器
register.filter('cut', cut)也可使用裝飾器
@register.filter(name='cut')
def cut(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
注:若是register.filter不聲明name參數,django將使用函數名看成過濾器名稱
例子:
# poll_extras.py定義過濾器 @register.filter def first_filter(intval1, intval2=1): return intval1 / intval2 # app_test.html使用過濾器 {% load poll_extras %} {{ 4 | first_filter:2 }} # 2.0 {{ 4 | first_filter }} # 4.0
注:大多數過濾器不接受參數。在這種狀況下,只需將參數排除在函數以外。例子:
def lower(value): # Only one argument. """Converts a string into all lowercase""" return value.lower()
若是您定義的過濾器須要限定第一個參數爲string類型,就可使用stringfilter裝飾器。
from django import template from django.template.defaultfilters import stringfilter register = template.Library() @register.filter @stringfilter def lower(value): return value.lower()
將filter返回的結果以原樣輸出,不進行轉義,一般包含HTML標籤使其在模板上正常顯示。
@register.filter(is_safe=True) def third_demo_filter(value): return '%s<h2>哈哈,</h2>' % value
使用mark_safe函數標記後,django將再也不對該函數的內容進行轉義。
@register.filter() def third_demo_filter(value): return mark_safe(value)
爲了讓過濾器知道當前的自動轉義狀態,在註冊過濾器函數時將needs_autoescape標誌設置爲True。(若是不指定此標誌,則默認爲False)。此標誌告訴Django,您的篩選器函數但願被傳遞一個額外的關鍵字參數,稱爲autoescape,若是自動轉義生效,則爲真,不然爲假。建議將autoescape參數的默認值設置爲True,這樣若是從Python代碼調用該函數,默認狀況下就啓用了轉義。
@register.filter(needs_autoescape=True) def initial_letter_filter(text, autoescape=True): print('result2', autoescape) first, other = text[0], text[1:] if autoescape: esc = conditional_escape else: esc = lambda x: x result = '<strong>%s</strong>%s' % (esc(first), esc(other)) print('autoescape',autoescape) # True return mark_safe(text)
當設置此標誌時,若是過濾器的第一個參數是時區感知的datetime, Django將根據模板中時區轉換的規則將其轉換爲當前時區。
@register.filter(expects_localtime=True) def businesshours(value): try: return 9 <= value.hour < 17 except AttributeError: return ''
django.template.Library.simple_tag()
若是模板標記須要訪問當前上下文,那麼在註冊標記時可使用takes_context參數。
@register.simple_tag(takes_context=True) def current_time(context, format_string): #注意,第一個參數必須稱爲context timezone = context['timezone'] return your_get_current_time_method(timezone, format_string)
@register.simple_tag def my_tag(a, b, *args, **kwargs): warning = kwargs['warning'] profile = kwargs['profile'] ... return ... # template調用 以空格做爲分隔將參數傳給標籤 {% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
注:能夠將標記結果存儲在模板變量中,而不是直接輸出它。這是經過使用變量名後面的as參數來完成的。這樣作可讓您本身在您認爲合適的地方輸出內容
{% current_time "%Y-%m-%d %I:%M %p" as the_time %} <p>The time is {{ the_time }}.</p>
首先,定義接受參數併爲結果生成數據字典的函數。這裏重要的一點是,咱們只須要返回一個字典,而不是任何更復雜的東西。這將用做模板片斷的模板上下文
def show_results(poll): choices = poll.choice_set.all() return {'choices': choices}
接下來,建立用於呈現標記輸出的模板。此模板是標記的固定特性:標記編寫器指定它,而不是模板設計器。按照咱們的示例,模板很是簡單
<ul> {% for choice in choices %} <li> {{ choice }} </li> {% endfor %} </ul>
如今,經過調用Library對象上的inclusion_tag()方法來建立並註冊包含標記。按照咱們的示例,若是上面的模板在一個名爲results的文件中。html在一個由模板加載器搜索的目錄中,咱們會這樣註冊標籤:
# Here, register is a django.template.Library instance, as before @register.inclusion_tag('results.html') def show_results(poll): ...
另外,也可使用django.template來註冊包含標籤。模板實例:
from django.template.loader import get_template t = get_template('results.html') register.inclusion_tag(t)(show_results)
takes_context上下文
@register.inclusion_tag('link.html', takes_context=True) def jump_link(context): # home_link是views.py傳給template的值 return { 'link': context['home_link'], 'title': context['home_title'], }
from django import template import datetime register = template.Library() def do_current_time(parser, token): # 註冊方法 try: # split_contents() knows not to split quoted strings. tag_name, format_string = token.split_contents() except ValueError: raise template.TemplateSyntaxError( "%r tag requires a single argument" % token.contents.split()[0] ) if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")): raise template.TemplateSyntaxError( "%r tag's argument should be in quotes" % tag_name ) return CurrentTimeNode(format_string[1:-1]) class CurrentTimeNode(template.Node): # 節點 def __init__(self, format_string): self.format_string = format_string def render(self, context): # 節點實際運行的方法 return datetime.datetime.now().strftime(self.format_string) register.tag('current_time', do_current_time) # 註冊
class CycleNode(template.Node): def __init__(self, cyclevars): self.cyclevars = cyclevars def render(self, context): if self not in context.render_context: context.render_context[self] = itertools.cycle(self.cyclevars) cycle_iter = context.render_context[self] return next(cycle_iter)
# 調用 <p>This post was last updated at {% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.</p> from django import template def do_format_time(parser, token): try: # split_contents() knows not to split quoted strings. tag_name, date_to_be_formatted, format_string = token.split_contents() except ValueError: raise template.TemplateSyntaxError( "%r tag requires exactly two arguments" % token.contents.split()[0] ) if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")): raise template.TemplateSyntaxError( "%r tag's argument should be in quotes" % tag_name ) return FormatTimeNode(date_to_be_formatted, format_string[1:-1]) class FormatTimeNode(template.Node): def __init__(self, date_to_be_formatted, format_string): self.date_to_be_formatted = template.Variable(date_to_be_formatted) self.format_string = format_string def render(self, context): try: actual_date = self.date_to_be_formatted.resolve(context) return actual_date.strftime(self.format_string) except template.VariableDoesNotExist: return ''
一般,若是您的模板標記設置了模板變量而不是輸出值,則會更加靈活。這樣,模板做者就能夠重用模板標記建立的值。
要在上下文中設置變量,只需對render()方法中的上下文對象使用字典賦值。下面是CurrentTimeNode的更新版本,它設置了一個模板變量current_time,而不是輸出它:
import datetime from django import template class CurrentTimeNode2(template.Node): def __init__(self, format_string): self.format_string = format_string def render(self, context): context['current_time'] = datetime.datetime.now().strftime(self.format_string) return '' #調用 {% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
注:上下文中的任何變量集都只能在分配它的模板的相同塊中可用。這種行爲是有意的;它爲變量提供了一個做用域,這樣它們就不會與其餘塊中的上下文發生衝突。
可是,CurrentTimeNode2有一個問題:變量名current_time是硬編碼的。這意味着您須要確保您的模板在其餘地方不使用{{current_time}},由於{% current_time %}將盲目地覆蓋該變量的值。更清晰的解決方案是讓模板標記指定輸出變量的名稱,以下所示:
#調用 {% current_time "%Y-%M-%d %I:%M %p" as my_current_time %} <p>The current time is {{ my_current_time }}.</p> import re class CurrentTimeNode3(template.Node): def __init__(self, format_string, var_name): self.format_string = format_string self.var_name = var_name def render(self, context): context[self.var_name] = datetime.datetime.now().strftime(self.format_string) return '' def do_current_time(parser, token): # This version uses a regular expression to parse tag contents. try: # Splitting by None == splitting by spaces. tag_name, arg = token.contents.split(None, 1) except ValueError: raise template.TemplateSyntaxError( "%r tag requires arguments" % token.contents.split()[0] ) m = re.search(r'(.*?) as (\w+)', arg) if not m: raise template.TemplateSyntaxError("%r tag had invalid arguments" % tag_name) format_string, var_name = m.groups() if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")): raise template.TemplateSyntaxError( "%r tag's argument should be in quotes" % tag_name ) return CurrentTimeNode3(format_string[1:-1], var_name)
模板標籤能夠協同工做。例如,標準的{% comment %}標籤會隱藏全部內容,直到{% endcomment %}。要建立這樣的模板標記,在編譯函數中使用parser.parse()。
下面是如何實現簡化的{% comment %}標籤:
def do_comment(parser, token):
nodelist = parser.parse(('endcomment',))
parser.delete_first_token()
return CommentNode()
class CommentNode(template.Node): def render(self, context): return ''
parse()使用塊標記的一個元組名稱「解析到」。它返回一個django.template的實例。NodeList,它是解析器在遇到元組中的任何標記以前遇到的全部節點對象的列表。
在上述示例中的「nodelist = parser.parse(('endcomment',))」中,nodelist是{% comment %}和{% endcomment %}之間的全部節點的列表,不包括{% comment %}和{% endcomment %}自己。
在調用parser.parse()以後,解析器尚未「使用」{% endcomment %}標記,所以代碼須要顯式地調用parser.delete_first_token()。
render()只返回一個空字符串。{% comment %}和{% endcomment %}之間的任何內容都被忽略
{% comment %}的實際實現略有不一樣,由於它容許在{% comment %}和{% endcomment %}之間出現損壞的模板標記。它經過調用parser.skip_past('endcomment')而不是parser.parse((('endcomment'),)),後面跟着parser.delete_first_token(),從而避免了節點列表的生成。