自定义Tag

在Django Template中使用自定义Tag步骤:



  1. 在Django App下建立一个templatetags目录。


  2. 在templateapp目录中增加2个文件,一个是__init__.py,另一个是tag文件。比如{% load your_tag %},那么就需要建立一个your_tag.py文件。{% load %}关联INSTALLED_APPS。



  3. 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 %},可以看出这里就不需要参数了。