django自定义模板标签和过滤器

Django虽然为咱们内置了二十多种标签和六十多种过滤器,可是需求是各类各样的,总有一款你cover不到。Django为咱们提供了自定义的机制,能够经过使用Python代码,自定义标签和过滤器来扩展模板引擎,而后使用{% load %}标签。html

1、前置步骤

Django对于自定义标签和过滤器是有前置要求的,首先一条就是代码布局和文件组织。django

你能够为你的自定义标签和过滤器新开一个app,也能够在原有的某个app中添加。服务器

无论怎么样,第一步,在app中新建一个templatetags(名字固定,不能变,只能是这个),和views.py、models.py等文件处于同一级别目录下。这是一个包!不要忘记建立__init__.py文件以使得该目录能够做为Python的包。app

在添加templatetags包后,须要从新启动服务器,而后才能在模板中使用标签或过滤器。函数

  • 将你自定义的标签和过滤器将放在templatetags包下的一个模块里。布局

  • 这个模块的名字是后面载入标签时使用的标签名,因此要谨慎的选择名字以防与其余应用下的自定义标签和过滤器名字冲突,固然更不能与Django内置的冲突。spa

假设你自定义的标签/过滤器在一个名为poll_extras.py的文件中,那么你的app目录结构看起来应该是这样的:code

polls/
    __init__.py
    models.py
    templatetags/
        __init__.py
        poll_extras.py
    views.py

为了让{% load xxx %}标签正常工做,包含自定义标签的app必须在INSTALLED_APPS中注册。而后你就能够在模板中像以下这样使用:orm

{% load poll_extras %}

在templatetags包中放多少个模块没有限制。只须要记住{% load xxx %}将会载入给定模块名中的标签/过滤器,而不是app中全部的标签和过滤器。htm

要在模块内自定义标签,首先,这个模块必须包含一个名为register的变量,它是template.Library的一个实例,全部的标签和过滤器都是在其中注册的。 因此把以下的内容放在你的模块的顶部:

from django import template register = template.Library() 

友情提示:能够阅读Django的默认过滤器和标记的源代码。它们分别位于django/template/defaultfilters.pydjango/template/defaulttags.py中。它们是最好的范例!

2、自定义模板过滤器

1. 编写过滤器

自定义过滤器就是一个带有一个或两个参数的Python函数

注意:这个Python函数的第一个参数是你要过滤的对象,第二个参数才是你自定义的参数。并且最多总共只能有两个参数,因此你只能自定义一个参数!这是过滤器的先天限制。

  • 变量的值:不必定是字符串形式。
  • 参数的值:能够有一个初始值,或者彻底不要这个参数。

例如,在{{ var|foo:"bar" }}中,foo过滤器应当传入变量var和参数"bar"。

因为模板语言没有提供异常处理,任何从过滤器中抛出的异常都将会显示为服务器错误。

下面是一个定义过滤器的例子:

def cut(value, arg): """将value中的全部arg部分切除掉""" return value.replace(arg, '') 

下面是这个过滤器的使用方法:

{{ somevariable|cut:"0" }}

大多数过滤器没有参数,在这种状况下,你的过滤器函数不带额外的参数便可,但基本的value参数是必带的。例如:

def lower(value): # Only one argument.
    """Converts a string into all lowercase"""
    return value.lower()

2. 注册过滤器

类原型:django.template.Library.filter()

一旦你写好了过滤器函数,就须要注册它,方法是调用register.filter,好比:

register.filter('cut', cut)
register.filter('lower', lower)

Library.filter()方法须要两个参数:

  • 过滤器的名称:一个字符串对象
  • 编译的函数 :你刚才写的过滤器函数

还能够把register.filter()用做装饰器,以以下的方式注册过滤器:

@register.filter(name='cut') def cut(value, arg): return value.replace(arg, '') @register.filter def lower(value): return value.lower() 

上面第二个例子没有声明name参数,Django将使用函数名做为过滤器的名字。

自定义过滤器就是这么简单,使用起来也和普通的过滤器没什么区别。咱们用Python的方式解决了HTML的问题。

3、自定义模板标签

标签比过滤器更复杂,由于标签能够作任何事情。Django提供了大量的快捷方式,使得编写标签比较容易。 对于咱们通常的自定义标签来讲,simple_tag是最重要的,它帮助你将一个Python函数注册为一个简单的模版标签。

1. simple_tag

原型:django.template.Library.simple_tag()

为了简单化模版标签的建立,Django提供一个辅助函数simple_tag,这个函数是django.template.Library的一个方法。

好比,咱们想编写一个返回当前时间的模版标签,那么current_time函数从而能够这样写︰

import datetime from django import template register = template.Library() @register.simple_tag def current_time(format_string): return datetime.datetime.now().strftime(format_string) 

关于simple_tag函数有几件值得注意的事项︰

若是不须要额外的转义,可使用mark_safe()让输出不进行转义,前提是你绝对确保代码中不包含XSS漏洞。 若是要建立小型HTML片断,强烈建议使用format_html()而不是mark_safe()

若是你的模板标签须要访问当前上下文,能够在注册标签时使用takes_context参数︰

@register.simple_tag(takes_context=True)
def current_time(context, format_string):
    timezone = context['timezone']
    return your_get_current_time_method(timezone, format_string)

请注意,第一个参数必须称做context!

若是你须要重命名你的标签,能够给它提供自定义的名称︰

register.simple_tag(lambda x: x - 1, name='minusone') @register.simple_tag(name='minustwo') def some_function(value): return value - 2 

simple_tag函数能够接受任意数量的位置参数和关键字参数。 像这样:

@register.simple_tag
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 %}

能够将标签结果存储在模板变量中,而不是直接输出。这是经过使用as参数后跟变量名来实现的:

{% current_time "%Y-%m-%d %I:%M %p" as the_time %} <p>The time is {{ the_time }}.</p> 

2. inclusion_tag()

原型:django.template.Library.inclusion_tag()

另外一种常见类型的模板标签是经过渲染一个模板来显示一些数据。例如,Django的Admin界面使用自定义模板标签显示"添加/更改"表单页面底部的按钮。这些按钮看起来老是相同,但连接的目标倒是根据正在编辑的对象而变化的。

这种类型的标签被称为"Inclusion 标签"。

下面,展现一个根据给定的tutorials中建立的Poll对象输出一个选项列表的自定义Inclusion标签。在模版中它是这么调用的:

{% show_results poll %}

而输出是这样的:

<ul>
  <li>First choice</li> <li>Second choice</li> <li>Third choice</li> </ul> 

具体的编写方法:

首先,编写Python函数:

def show_results(poll): choices = poll.choice_set.all() return {'choices': choices} 

接下来,建立用于标签渲染的模板results.html︰

<ul>
{% for choice in choices %} <li> {{ choice }} </li> {% endfor %} </ul> 

最后,经过调用Library对象的inclusion_tag()装饰器方法建立并注册Inclusion标签︰

@register.inclusion_tag('results.html')
def show_results(poll):
    ...

或者使用django.template.Template实例注册Inclusion标签︰

from django.template.loader import get_template t = get_template('results.html') register.inclusion_tag(t)(show_results) 

inclusion_tag函数能够接受任意数量的位置参数和关键字参数。像这样:

@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 %}

能够在标签中传递上下文中的参数。好比说,当你想要将上下文context中的home_linkhome_title这两个变量传递给模版。 以下所示:

@register.inclusion_tag('link.html', takes_context=True) def jump_link(context): return { 'link': context['home_link'], 'title': context['home_title'], } 

注意函数的第一个参数必须叫作context。context必须是一个字典类型。

register.inclusion_tag()这一行,咱们指定了takes_context=True和模板的名字。模板link.html很简单,以下所示:

Jump directly to <a href="{{ link }}">{{ title }}</a>. 

而后,当任什么时候候你想调用这个自定义的标签时,只须要load它自己,不须要添加任何参数,{{ link }}{{ title }}会自动从标签中获取参数值。像这样:

{% jump_link %}

使用takes_context=True,就表示不须要传递参数给这个模板标签。它会本身去获取上下文。

相关文章
相关标签/搜索