Django第十篇-----關於模板的高階話題---下半篇
目錄
自定義模板標籤和過濾器
Django 的模板語言自帶了豐富的標籤和過濾器,能滿足常見的表現邏輯需求。但是,這些內建的標籤和過濾器可能缺少你需要的功能。
我們可以擴充套件模板引擎,使用 Python 自定義標籤和過濾器,然後使用 {% load %} 標籤載入,讓自定義的標籤和過濾器可在模板中使用。
自定義模板過濾器
自定義的過濾器其實就是普通的 Python 函式,接受一個或多個引數:
1. 變數的值(輸入),不一定是字串。
2. 引數的值,可以有預設值,也可以留空。
例如,對 {{ var|foo:"bar" }} 來說,傳給 foo 過濾器的變數是 var ,引數是 "bar" 。因為模板語言沒有提供異常處理功能,所以模板過濾器丟擲的異常會以伺服器錯誤體現出來。
過濾器的定義:
def cut(value, arg):
"""Removes all values of arg from the given string"""
return value.replace(arg, '')
這個過濾器的用法舉例如下:
{{ somevariable|cut:"0" }}
多數過濾器沒有引數。此時,在函式中留空引數即可。例如:
def lower(value): # 只有一個引數
"""Converts a string into all lowercase"""
return value.lower()
註冊自定義的過濾器
定義好過濾器之後,要使用 Library 例項註冊,讓 Django 的模板語言知道它的存在:
register.filter('cut', cut)
register.filter('lower', lower)
Library.filter() 有兩個引數:
1. 過濾器的名稱,一個字串。
2. 負責處理過濾器的函式,一個 Python 函式(不是函式名稱的字串形式)。
register.filter() 也可以作為裝飾器使用:
@register.filter(name='cut')
def cut(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
自定義模板標籤
標籤能做任何事情,比過濾器複雜。Django 提供了一些快捷方式,簡化了多數標籤型別的編寫。首先,我們將探討這些快捷方式,然後說明在快捷方式不夠用時如何從頭開始編寫標籤。
例如有個 current_time 標籤,它接受一個格式字串,返回格式化後的時間字串
據此, current_time 函式可以這麼編寫:
import datetime
from django import template
register = template.Library()
@register.simple_tag
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
如果模板標籤需要訪問當前上下文,註冊標籤時指定 takes_context 引數:
@register.simple_tag(takes_context=True)
def current_time(context, format_string):
timezone = context['timezone']
return your_get_current_time_method(timezone, format_string)
如果想為標籤起個別的名稱,指定 name 引數:
register.simple_tag(lambda x: x - 1, name='minusone')
@register.simple_tag(name='minustwo')
def some_function(value):
return value - 2
使用 simple_tag 裝飾的函式可以接受任意個位置引數和關鍵字引數。例如:
@register.simple_tag
def my_tag(a, b, *args, **kwargs):
warning = kwargs['warning']
profile = kwargs['profile']
...
return ...
然後在模板中可以把任意個引數(以空格分開)傳給這個標籤。與 Python 程式碼一樣,關鍵字引數的值使用等號( = )設定,而且必須放在位置引數後面。例如:
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
引入標籤
首先,要定義一個接受引數的函式,生成一個字典,為結果提供資料。注意,我們只需返回一個字典,而不是其他複雜的資料結構。返回的字典在模板片段的上下文中使用。
def books_for_author(author):
books = Book.objects.filter(authors__id=author.id)
return {'books': books}
Author 物件名下的圖書列表。我們將像這樣使用這個標籤:
{% books_for_author author %}
得到的結果如下:
<ul>
<li>The Cat In The Hat</li>
<li>Hop On Pop</li>
<li>Green Eggs And Ham</li>
</ul>
然後,建立用於渲染標籤輸出的模板。對這個標籤來說,模板十分簡單:
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul