模板过滤器和标签
现在我们已经很熟悉Django的MTV模式了。模板(template)负责如何去展示数据,而视图(view)负责筛选出正确的数据。因此通常来说逻辑都是放到视图中的,但模板也需要一些和表示相关的逻辑 :比如循环展示(如{% for ... %} )、或者以某种特定格式输出(如{{ ...|date:'Y-m-d' }} )等,这些功能都是靠模板的**过滤器(filters) 和标签(tags)**实现的。
Django的模板语言包含了很多内置的过滤器和标签,设计目的是满足应用需要占位逻辑需求。但有的时候这些通用的功能满足不了你的某些需求,这时候就需要自定义过滤器和标签来实现了。
前置条件
要在Django中使用模板过滤器或标签,就首先得注册它们。
注册方法如下:
在APP中新建名为
templatetags的目录(方便起见,教程选择了article这个APP)在此目录中新建名为
__init__.py的空文件,使得此目录被视作一个Python的包在此目录中新建python文件(比如
my_filters_and_tags.py),就可以在里面愉快的写代码啦
完成后的目录结构如下:
请注意:
目录必须位于已注册的APP中,这是出于安全性的考虑
新建目录后,必须手动重启服务器,里面的过滤器和标签才能生效
前置条件就完成了,接下来我们看看如何写一个模板过滤器。
模板过滤器
过滤器filter的表现形式为紧跟在上下文后面的管道符| ,管道符后面是filter的名称: {{ ...|filter_name }} 。有的filter还可以带有参数: {{ ...|filter_name:var }}。
filter这个名字可能会让你误认为它只是用来筛选某些特定数据的,但实际上它远不止这点功能。它可以改变上下文的最终展示效果,也可以将上下文通过运算输出为特定的值。
小试牛刀
要成为一个可用的filter ,文件中必须包含一个名为 register 的模块级变量,它是一个 template.Library 实例,所有的filters均在其中注册。所以在my_filter_and_tags.py文件中输入以下内容:
接下来就可以像写普通的Python函数一样写过滤器了:
filter可以通过装饰器进行注册。若注册装饰器中携带了
name参数,则其值为此filter的名称;若未携带,则函数名就是filter的名称。filter必须是有一到两个参数的Python函数。第一个参数是上下文本身,第二个参数则由filter提供。举个栗子,在过滤器
{{ var|foo:"bar" }}中,变量var为第一个参数,变量bar则作为第二个参数。
调用这些filter的方法是在模板文件中用{% load ... %}将filter文件的名称加载进去,像这样:
更人性化的时间
了解完filter的使用方法后,下面来写点更实用的功能。
对人类这种生物来说, 相对时间通常比绝对时间要更容易阅读。 发表于 3天前可以轻易得知此文章刚发表不久;而发表于 2019年8月10日你还得想想今天到底几号来着。
因此写一个显示相对日期的time_since_zh过滤器:
代码功能很简单,就是将文章发布时间和当前时间作比较,然后返回适当的字符串。
修改文章列表模板文件中与发布时间相关的代码,把刚写的filter用上:
效果如下:

模板标签
模板标签(tag)比过滤器更复杂,功能也更强大。
标签tag的表现形式为{% tag_name ... %} ,比如我们非常熟悉的内置标签{% url ... %}、 {% static ... %}等。如果内置标签满足不了你的需求,Django 提供了很多快捷方式,简化了编写绝大多数类型的标签过程。
简单标签
simple_tag就是最重要的标签类型。标签的注册方法跟过滤器非常类似:
调用时同样记得在模板文件中用{% load... %}引入。用法你应该猜得到: {% change_http_to_https ... %} ,这个标签的作用是将http链接替换为https链接。
下面这个例子可以返回指定格式的时间字符串:
调用时你可以将其保存为模板变量,以便你在期望的位置多次调用:
模板标签也可以访问当前的上下文,只需要在注册标签时传入takes_context参数:
注意,第一个参数必须是context。
与过滤器不同的是,标签可以接受任意数量的位置或关键字参数。例如:
在模板中调用时,任意数量的、以空格分隔的参数会被传递给模板标签。与 Python 中类似,关键字参数的赋值使用等号(" = "),且必须在位置参数后提供:
包含标签
包含标签可以让另一个模板为当前模板渲染数据。听起来比较拗口,还是通过例子来理解。
假设现在有一个需求,是要在文章详情页面中,显示所有相关评论的发布时间。因此在my_filters_and_tags.py中写入:
函数传入的参数可以是模板中的上下文变量。函数体内部取得了所有相关评论的查询集,然后把结果comments返回。注意返回结果是进入到tag_list.html这个模板中去了,因此新建它并写入:
然后在文章详情页面的模板中,随便找一个位置写入:
刷新详情页面,顺利的话就能看到所有评论的发表时间都展示出来了。
包含标签的另一个应用场景就是各种按钮了。有的按钮看上去长得都差不多,但是根据页面不同会有不同的功能,这时候也可以用包含标签来实现。
总之,包含标签可以将常用的模板代码打包成小组件,方便重复利用。
总结
模板过滤器和标签,可以完成和表示相关的逻辑 ,从而使视图专注于业务核心逻辑,有利于组件化和逻辑分离。随着学习的深入,会逐渐体会到它的重要性。
本章对它们做了入门介绍,以便读者对其有初步的概念。更详细的解释请进一步阅读Django官方文档。
项目完整代码: Django_blog_tutorial