Django之自定义模板标签filter,simple_tag,inclusion_tags之间的区别
自定义模板(template)的标签(tags)和过滤器(filters)
- filter
- simple_tag
- inclusion_tag
布局
1.在app中创建templatetags模块
与 models.py, views.py 等同级。若该目录不存在,创建它——不要忘了用 __init__.py 文件确保目录被视作一个 Python 包。
*添加templatetags模块后,你需要重启服务器,这样才能在模板中使用 tags 和 filters。*
2.创建任意 .py 文件,如:xx.py
小心不要采用一个可能与其它应用自定义的 tags 和 filters 冲突的名字
3.py文件需要注册,在py文件中写入以下代码
from django import template
register = template.Library()
4.html模板需要导入模块
{% load 模块名 %}
#如{% load poll_extras %},{% load xx %}
编写自定义的模板过滤器filter
过滤器,如 {{ var|foo:"bar" }}只有两个参数,一个是变量值var,一个是过滤器的参数bar
特点:只能两个参数,不能加空格,能做if条件
html:{ 参数1|函数名:参数2}
自定义filter
django.template.Library.filter()
第一种写法
1.定义函数
def cut(value, arg):
"""Removes all values of arg from the given string"""
return value.replace(arg, '')
def lower(value): # Only one argument.
"""Converts a string into all lowercase"""
return value.lower()
2.用Library 实例去注册它
register.filter('cut', cut)
register.filter('lower', lower)
#register.filter() 方法有两个参数:
#1.过滤器的名称——字符串。
#2.编辑函数——一个 Python 函数(不是函数名的字符串)。
第二种写法,装饰器
@register.filter(name='cut')
def cut(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
#若你不填 name 参数,像第二个例子展示的一样,Django 会将函数名当做过滤器名。
filter()其他参数
register.filter() 也接受 3 个关键字参数, is_safe, needs_autoescape,和 expects_localtime
@register.filter(is_safe=True)
#安全字符串:是在输出时被标记为安全的字符串,不会进一步转义,即XSS 攻击
#该标志告诉 Django,若一个“安全”字符串传给您的过滤器,结果仍会是安全的。若传入了不安全的字符串,Django 会在需要时自动转义。
@register.filter(needs_autoescape=True)
#自动转义
@register.filter(expects_localtime=True)
#设置该标志后,如果过滤器接收的第一个参数是一个时区敏感的 datetime,Django 在将其传递给过滤器前的某个合适时间将其转换为当前时区的时间
自定义模板标签simple_tag()
特点:可以带多个参数,不能作为if条件
html:{% 函数名 arg1 arg2 arg3%}
返回值是字符串形式
simple_tag()定义
@register.simple_tag
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
#simple_tag 函数可以接受任意数量的位置或关键字参数
@register.simple_tag
def str_join(*args,**kwargs):
return '{}_{}'.format('_'.join(args),'*'.join(kwargs.values()))
@register.simple_tag
def my_tag(a, b, *args, **kwargs):
warning = kwargs['warning']
profile = kwargs['profile']
...
return ...
Html模板中
#任意数量的,以空格分隔的参数会被传递给模板标签。与 Python 中类似,关键字参数的赋值使用等号("`=`"),且必须在位置参数后提供。例子:
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
#将标签结果存入一个模板变量而不是直接将其输出是可能的。这能通过使用 as 参数,后跟变量名实现。这样做能让你在期望的位置输出内容:
{% current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>
simple_tag()其他参数
#模板标签需要访问当前上下文
@register.simple_tag(takes_context=True)
def current_time(context, format_string):
timezone = context['timezone']
return your_get_current_time_method(timezone, format_string)
#需要重命名标签,你可以为其提供一个自定义名
register.simple_tag(lambda x: x - 1, name='minusone')
@register.simple_tag(name='minustwo')
def some_function(value):
return value - 2
包含标签inclusion_tag()
特点:可以带多个参数,
返回值的参数,变量,需要给模板渲染
定义
第一种方式定义
#步骤
#1定义一个函数,接受参数,并返回一个字典,只需返回一个字典,不是任何其它复杂的东西。这将作为一个模板上下文被模板碎片使用
def show_results(poll):
choices = poll.choice_set.all()
return {'choices': choices}
#2创建模板,HTML
<ul>
{% for choice in choices %}
<li> {{ choice }} </li>
{% endfor %}
</ul>
#3使用标签
{% show_results poll %}
#结果
<ul>
<li>First choice</li>
<li>Second choice</li>
<li>Third choice</li>
</ul>
第二方式
# Here, register is a django.template.Library instance, as before
@register.inclusion_tag('results.html')#results.html模板,在模板加载器搜索的目录中
def show_results(poll):
...
或者,也能用 [django.template.Template]实例注册包含标签:
from django.template.loader import get_template
t = get_template('results.html')
register.inclusion_tag(t)(show_results)
总之,常用的写法第二种方式,用装饰器
inclusion_tag()参数
#有时候,你的包含标签可能要求超多参数,模板作者不得不传入所有参数,并牢记它们的顺序,非常痛苦。为了解决此问题, Django 为包含标签提供了一个 take_context 选项。如果在创建模板标签时指定了 takes_context,该标签将没有必要的参数,底层 Python 函数将只有一个参数——标签创建时的模板上下文。
#举个例子,假设你编写了一个包含标签,总会在一个包含指向首页的 home_link 和 home_title 的上下文环境下使用。Python 函数看起来会像这样:
@register.inclusion_tag('link.html', takes_context=True)
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
#注意,该函数的第一个参数 必须 是 context。
#在 register.inclusion_tag() 行,我们制定了模板名并设置 takes_context=True。以下是模板 link.html 的样子:
Jump directly to <a href="{{ link }}">{{ title }}</a>.
#后面,当你想用该自定义标签时,加载它的库,并不带任何参数的调用它,像这样:
{% jump_link %}
注意,只要使用了 takes_context=True,就无需为模板标签传递参数。它自动从上下文获取。
takes_context 参数默认为 False。当其为 True,标签会被传入上下文对象,像本例展示的那样。这是本例和之前的 包含标签 实例的唯一不同之处。
包含标签 函数能接受任意个数的位置或关键字参数。例子:
@register.inclusion_tag('my_template.html')
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 %}
动态页面方便
三者之间的比较
三者共同点:前提布局是一样的
写函数 + 加装饰器
#filter只能两个参数,可以用if判断语句
@register.filter
def add_arg(value,arg):
return 'xxxx'
#simple_tag可以多个参数,不可以用if判断语句,返回数据是以字符串形式,比较单一
@register.simple_tag
def str_join(*args, **kwargs):
return "{}_{}".format('_'.join(args), '*'.join(kwargs.values()))
#可以多个参数,不可以用if判断语句,数据返回字典形式,可复杂操作
@register.inclusion_tag('page.html')
def pagination(num):
return {'num': range(1, num + 1)}
inclusion_tag的模板page.html
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% for li in num %}
<li><a href="#">{{ li }}</a></li>
{% endfor %}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
模板html使用
#共同点:导入库
{% load 模块名 %}
{% load mytags %}
#不同点
#filter
{{ somevariable|cut:"0" }} #是以两个大括号括起来的
{{ 'alex'|add_arg:'dsb' }}
#simple_tag
#inclusion_tag
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %} #两者相同,是以大括号内包含百分号包裹
{% str_join 'a' 'b' 'c' k1='d' k2='e' k3='f' %}
{% pagination 10 %}
simple_tag与inclusion_tag之间的对比示例
比如下面做个分页,
首先,两者前提都在app下创建templatetags,在templatetags里创建mytags.py文件
simple_tag写法
from django import template
register = template.Library()
from django.utils.safestring import mark_safe #告诉django此代码是安全性的,不需要转义
@register.simple_tag
def pagination(num):
li_list = [ '<li><a href="#">{}</a></li>'.format(i) for i in range(1,num+1) ]
return mark_safe("""
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>""".format(''.join(li_list)))
inclusion_tag写法
mytags.py文件
from django import template
register = template.Library()
from django.utils.safestring import mark_safe
@register.inclusion_tag('page.html')
def pagination(num):
return {'num': range(1, num + 1)}
模板page.html文件
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% for li in num %}
<li><a href="#">{{ li }}</a></li>
{% endfor %}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
HTML使用
两者的使用方法相同
{% load mytags %} #导入
{% pagination 3 %} #函数名 +参数
浙公网安备 33010602011771号