自定义Tag
在Django Template中使用自定义Tag步骤:
在Django App下建立一个templatetags目录。
在templateapp目录中增加2个文件,一个是__init__.py,另一个是tag文件。比如{% load your_tag %},那么就需要建立一个your_tag.py文件。{% load %}关联INSTALLED_APPS。
from django import template
register=template.library()
示例代码参考:django/template/defaultfilters.py
django/template/defaulttags.py
自定义Tag有几种写法:
方法一:
<p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
首先在current_time.py中写入如下代码:
from django import template
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[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])
* parser是一个template parser对象,在这个方法中没有用到
* token.contents的内容就是current_time "%Y-%m-%d %I:%M %p"
* token.split_contents()是一个输入进行分割解析的方法,但重要的是它不会去解析引号括其来的部分,这里current_time "%Y-%m-%d %I:%M %p"被解析成current_time和"%Y-%m-%d %I:%M %p",另外还有一个方法是token.contents.split()这个方法会解析引号括起来的部分,所以通常用token.split_contents()
* django.template.TemplateSyntaxError是用来抛出异常的,对于处理错误非常方便,不需要另外写错误处理页面
接着,在current_time.py中需要写入:
from django import template
import datetime
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)
* render()方法是自定义Tag真正工作的部分
* 在render()中不需要抛出异常,包括SyntaxError
最后,在current_time.py中写入:
register.tag('current_time', do_current_time)
* tag方法的第一个参数是自定义Tag名字,字符型
* 第二个参数就是传递所调用的方法名字
Django在解析一个tag时候,是每遇到一个tag标签,那么就实例话为template.Node类,然后自动调用Node类的render()方法来完成相关事情。
方法二:
有时候为了更加的简单,可以使用register.simple_tag()方法来注册一个自定义类:
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
register.simple_tag(current_time)
* 在使用current_time tag时后面跟的参数已经不需要手工处理,simple_tag方法在调用时会自动处理参数
* 引号括起来的参数部分会自动处理为plain text(普通文本)
* 如何参数是一个template变量,那么该方法会处理成变量的值,而不是该变量本身
方法三:
另一种常见的tag类型是inclusion tag。比如要使用{% show_results poll %},其输出为:
<ul>
<li>First choice</li>
<li>Second choice</li>
<li>Third choice</li>
</ul>
在show_results.py中增加如下代码:
def show_results(poll):
choices = poll.choice_set.all()
return {'choices': choices}
# Here, register is a django.template.Library instance, as before
register.inclusion_tag('results.html')(show_results)
results.html内容为:
<ul>
{% for choice in choices %}
<li> {{ choice }} </li>
{% endfor %}
</ul>
此外还有一种特殊情况是在tag中不带参数,使用context作为默认参数。
# The first argument *must* be called "context" here.
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
# Register the custom tag as an inclusion tag with takes_context=True.
register.inclusion_tag('link.html', takes_context=True)(jump_link)
这里register.inclusion_tag()方法带了第二个参数takes_context=True,此时就可以在link.html中这样使用:
Jump directly to <a href="{{ link }}">{{ title }}</a>
这时,在template中使用该自定义Tag可以这样: {% jump_link %},可以看出这里就不需要参数了。