程式語言:Python
Package:Django
Django 官網文件
簡介:自定義 Tags & Filter
範例
範例
範例
例:一個能夠產生指定作者對象的書籍清單的標籤。結果如下
有時候,包含標籤需要訪問父模板的 context。
可使用 takes_context 選項。注意函數的第一個參數必須是 context。
例:一個包含標籤,該標籤包含有指向主頁的 home_link 和 home_title 變量
Package:Django
Django 官網文件
簡介:自定義 Tags & Filter
初步設置
- 在 APP 下建立 templatetags 資料夾
- 資料夾下建立 __init__.py,並建立 mine.py (可自行命名)
- 在 template html 中,加入 {% load mine%}
- 在 mine.py 頂端加入
from django import template register = template.Library()
自定義 template filters
可定義參數- 輸入變數的值
- 參數的值,可以是默認值或者完全留空
# template html
{{ somevariable|cut:"0" }}
# in mine.py
#register.filter('cut', cut)
@register.filter(name='cut')
def cut(value, arg):
"""Removes all values of arg from the given string"""
return value.replace(arg, '')
# template html
{{ somevariable|lower}}
# in mine.py
#register.filter('lower', lower)
@register.filter
def lower(value): # Only one argument.
"""Converts a string into all lowercase"""
return value.lower()
自定義 template tags
當 Django 編譯一個模板時- 將原始模板分成一個個 節點。
- 每個節點都是 django.template.Node 的一個實例,並且具備 render() 方法。
範例
# template html
<p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
# in mine.py
from django import template
register = template.Library()
import datetime
class CurrentTimeNode(template.Node):
def __init__(self, format_string):
self.format_string = str(format_string)
def render(self, context):
now = datetime.datetime.now()
return now.strftime(self.format_string)
#register.tag('current_time', do_current_time)
@register.tag(name="current_time")
def do_current_time(parser, token):
try:
# split_contents() knows not to split quoted strings.
tag_name, format_string = token.split_contents()
except ValueError:
msg = '%r tag requires a single argument' % token.split_contents()[0]
raise template.TemplateSyntaxError(msg)
return CurrentTimeNode(format_string[1:-1])
- 每個標籤編譯函數有兩個參數,parser 和 token。
- parser是模板解析器對象。此例無使用。可看後面的例子
- token是被解析的語句。
- token.contents 是包含有標籤原始內容的字符串。
- 此例為 'current_time "%Y-%m-%d %I:%M %p"' 。
- token.split_contents() 按空格拆分,並保證引號中的字串不拆分。
- 避免使用 token.contents.split(),因可能會拆分字串中的空白
- 可拋出 django.template.TemplateSyntaxError
- 提供所有語法錯誤的有用信息。
- token.split_contents()[0] 記錄標籤的名字,就算標籤沒有任何參數。此例為 current_time
- 返回一個 CurrentTimeNode ,包含了節點需要知道的關於這個標籤的全部信息。
- 此例只傳遞了參數 "%Y-%m-%d %I:%M %p"。
- 雙引號使用 format_string[1:-1] 去除。
- 模板標籤編譯函數必須返回一個 Node 子類,返回其它值都是錯的。
# template html
{% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
<p>The current time is {{ my_current_time }}.</p>
# in mine.py
import re
class CurrentTimeNode3(template.Node):
def __init__(self, format_string, var_name):
self.format_string = str(format_string)
self.var_name = var_name
def render(self, context):
now = datetime.datetime.now()
context[self.var_name] = 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:
msg = '%r tag requires arguments' % token.contents[0]
raise template.TemplateSyntaxError(msg)
m = re.search(r'(.*?) as (\w+)', arg)
if m:
fmt, var_name = m.groups()
else:
msg = '%r tag had invalid arguments' % tag_name
raise template.TemplateSyntaxError(msg)
if not (fmt[0] == fmt[-1] and fmt[0] in ('"', "'")):
msg = "%r tag's argument should be in quotes" % tag_name
raise template.TemplateSyntaxError(msg)
return CurrentTimeNode3(fmt[1:-1], var_name)
block tag
範例# template html
{% upper %}
This will appear in uppercase, {{ user_name }}.
{% endupper %}
# in mine.py
def do_upper(parser, token):
nodelist = parser.parse(('endupper',))
parser.delete_first_token()
return UpperNode(nodelist)
class UpperNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
output = self.nodelist.render(context)
return output.upper()
- parser.parse() 的參數為 tuple,內含需要分析的模板標籤名
- 返回一個 django.template.NodeList 實例
- 包含了所有 Node 對象的列表
- 解析器在 tuple 指定的標籤之前遇到的內容
- nodelist 不包括開始跟結束標籤,此例為 {% upper %} 和 {% endupper %}。
- parser.parse() 被調用後,分析器並無清除 {% endcomment %} 標籤,因此需要調用 parser.delete_first_token() 來防止該標籤被處理兩次。
- 更多的範例可看 django/template/defaulttags.py
Simple tags
- 傳遞給函數只有單個參數。
- 函數被調用時,檢查必需參數個數的工作已經完成,無需再做這個工作。
- 參數兩邊的引號(如果有的話)已被截掉,只會接收到一個普通字符串。
範例
import datetime
from django import template
register = template.Library()
#{% current_time1 "%Y-%m-%d %I:%M %p" %}
@register.simple_tag
def current_time1(format_string):
return datetime.datetime.now().strftime(format_string)
#{% current_time2 "%Y-%m-%d %I:%M %p" %}
@register.simple_tag(takes_context=True)
def current_time2(context, format_string):
timezone = context['timezone']
return your_get_current_time_method(timezone, format_string)
#{% minusone 2 %} => 1
register.simple_tag(lambda x: x - 1, name='minusone')
#{% minustwo 2 %} => 0
@register.simple_tag(name='minustwo')
def some_function(value):
return value - 2
#{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
@register.simple_tag
def my_tag(a, b, *args, **kwargs):
warning = kwargs['warning']
profile = kwargs['profile']
...
return ...
#{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
#<p>The time is {{ the_time }}.</p>
Inclusion tags
通過渲染 其他 template 顯示數據範例
例:一個能夠產生指定作者對象的書籍清單的標籤。結果如下
- The Cat In The Hat
- Hop On Pop
- Green Eggs And Ham
# template html
{% books_for_author author %}
# in mine.py
#register.inclusion_tag('book_snippet.html')(books_for_author)
@register.inclusion_tag('book_snippet.html')
def books_for_author(author):
books = Book.objects.filter(authors__id=author.id)
return {'books': books}
# in book_snippet.html
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
有時候,包含標籤需要訪問父模板的 context。
可使用 takes_context 選項。注意函數的第一個參數必須是 context。
例:一個包含標籤,該標籤包含有指向主頁的 home_link 和 home_title 變量
# template html
{% jump_link %}
# in mine.py
@register.inclusion_tag('link.html', takes_context=True)
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
# in link.html
Jump directly to <a href="{{ link }}">{{ title }}</a>.
留言
張貼留言