- Template加載機制
擴展你的模板系統
創建模板庫
實現自定義過濾器
1. 創建register變量
register = template.Library()
2. 定義過濾器函數
#移除字符串中var的arg字串
return var.replace(arg, '')
"Converts a string into all lowercase"
return value.lower()
3. 註冊過濾器函數
#第二個就是你的過濾器函數引用名
register.filter('remove', remove)
register.filter('lower', lower)
def remove(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
register = template.Library()
@register.filter(name='remove')
def remove(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
實現自定義tag
瞭解模板編譯過程
{% ifequal name.birthday today %}
Happy birthday!
{% else %}
Be sure to come back on your birthday
for a splendid surprise message.
{% endifequal %}
- Text node: "Hello, "
- Variable node: person.name
- Text node: ".\n\n"
- IfEqual node: name.birthday and today
創建tag實戰
1. 定義Node節點類,實現render方法
from django import template
#這一句還是要的
register = template.Library()
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)
2. 創建Compilation函數
try:
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])
3. 註冊tag
def do_current_time(parser, token):
# ...
@register.tag
def shout(parser, token):
# ...
import datetime
register = template.Library()
@register.filter(name='remove')
def remove(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
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)
def do_current_time(parser, token):
try:
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])
register.tag('current_time', do_current_time)
4. 運行
複雜的實現自定義tag的其他幾種方法
1. 在Node類的render函數中設置context
now = datetime.datetime.now()
#設置context對象的值
context['current_time'] = now.strftime(self.format_string)
# render函數一定要返回字符串,即使是空串
return ''
<p>The time is {{ current_time }}.</p>
<p>The current time is {{ my_current_time }}.</p>
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):
#使用正規表達式來處理token
try:
# 使用string.split(sep[, maxsplit]),1代表最大分割數,也就是
# 分割後會產生maxsplit+1個元素
# 這裏分割後的結果爲(get_current_time, '"%Y-%M-%d %I:%M %p" as my_current_time')
tag_name, arg = token.contents.split(None, 1)
except ValueError:
msg = '%r tag requires arguments' % token.contents.split_contents()[0]
raise template.TemplateSyntaxError(msg)
#使用()代表正則組,匹配as兩邊的字符串
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)
# [1:-1]去除格式兩邊的引號
return CurrentTimeNode3(fmt[1:-1], var_name)
register.tag('get_current_time', do_current_time)
2. 實現塊作用區域的tag
nodelist = parser.parse(('endcomment',))
parser.delete_first_token()
return CommentNode()
class CommentNode(template.Node):
def render(self, context):
return ''
3. 在塊作用tag中保留context內容
This will appear in uppercase, {{ user_name }}.
{% endupper %}
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()
4. 快速創建簡單tag的方法
try:
return datetime.datetime.now().strftime(str(format_string))
except UnicodeEncodeError:
return ''
register.simple_tag(current_time)
def current_time(token):
# ...
5. 創建Inclusion Tag
<li>The Cat In The Hat</li>
<li>Hop On Pop</li>
<li>Green Eggs And Ham</li>
</ul>
- 定義函數
books = Book.objects.filter(authors__id=author.id)
return {'books': books}
- 創建另一個模板文件book_snippet.html
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
- 註冊tag
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
創建自定義模板加載類
from django.template import TemplateDoesNotExist
import zipfile
def load_template_source(template_name, template_dirs=None):
"Template loader that loads templates from a ZIP file."
#從settings.py配置文件中讀取屬性TEMPLATE_ZIP_FILES的值,默認返回空列表
template_zipfiles = getattr(settings, "TEMPLATE_ZIP_FILES", [])
# Try each ZIP file in TEMPLATE_ZIP_FILES.
for fname in template_zipfiles:
try:
z = zipfile.ZipFile(fname)
source = z.read(template_name)
except (IOError, KeyError):
continue
z.close()
# 找到一個可用的文件就返回
template_path = "%s:%s" % (fname, template_name)
return (source, template_path)
# 如果一個zip文件沒找到,報錯
raise TemplateDoesNotExist(template_name)
# 設置爲可用
load_template_source.is_usable = True
'books.zip_loader.load_template_source',
)