Django自定义模板
Django自定义模板
现在我们已经很熟悉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 ),就可以在里面愉快的写代码啦
完成后的目录结构如下:
article/ __init__.py views.py models.py # 新增目录 templatetags/ __init__.py # 空文件 my_filters_and_tags.py # 即将写代码的地方
请注意:
- 目录必须位于已注册的APP中,这是出于安全性的考虑
- 新建目录后,必须手动重启服务器,里面的过滤器和标签才能生效
前置条件就完成了,接下来我们看看如何写一个模板过滤器。
注册模板
要成为一个可用的 filter ,文件中必须包含一个名为register
的模块级变量,它是一个 template.Library
实例,所有的 自定义模板 均在其中注册。所以在 my_filter_and_tags.py
文件中输入以下内容:
article/templatetags/my_filter_and_tags.py:
from django import template # 进行注册 register = template.Library()
模板过滤器@register.filter
filter 这个名字可能会让你误认为它只是用来筛选某些特定数据的,但实际上它远不止这点功能。它可以改变上下文的最终展示效果,也可以将上下文通过运算输出为特定的值。
接下来就可以像写普通的Python函数一样写过滤器了:
article/templatetags/my_filter_and_tags.py:
from django import template register = template.Library() @register.filter(name='transfer') def lower(num1,num2): """将传进来的两个值进行相加""" return num1+num2 @register.filter() def lower(value): """将字符串转换为小写字符""" return value.lower()
filter通过装饰器进行注册。若注册装饰器中携带了 name 参数,则其值为此filter的名称;若未携带,则函数名就是filter的名称。
filter必须是有一到两个参数的Python函数。
第一个参数是上下文本身,第二个参数则由filter提供。举个栗子,在过滤器 {{ var|foo:"bar" }}
中,变量 var 为第一个参数,变量 bar 则作为第二个参数。
调用这些filter的方法是在模板文件中用 {% load ... %}
将filter文件的名称加载进去,像这样:
# 任意模板文件中 {% load my_filters_and_tags %} # 引入自定义模板文件 {{ 2|transfer:2 }} #输出:4 {{ 'ABC'|lower }} # 输出:'abc'
模板标签@register.simple_tag
模板标签(tag)比过滤器更复杂,功能也更强大。
标签 tag 的表现形式为 {% tag_name ... %} ,比如我们非常熟悉的内置标签 {% url ... %} 、 {% static ... %} 等。如果内置标签满足不了你的需求,Django 提供了很多快捷方式,简化了编写绝大多数类型的标签过程。
创建简单标签
simple_tag 就是最重要的标签类型。标签的注册方法跟过滤器非常类似
与过滤器不同的是,标签可以接受任意数量的位置或关键字参数。例如:
@register.simple_tag def my_tag(a, b, *args, **kwargs): #可以接收多个参数 warning = kwargs['warning'] profile = kwargs['profile'] 。。。。 return 。。。。
模板中使用
在模板中调用时,任意数量的、以空格分隔的参数会被传递给模板标签。与 Python 中类似,关键字参数的赋值使用等号(" = "),且必须在位置参数后提供:
# 任意模板文件中 {% load my_filters_and_tags %} # 引入自定义模板文件 {% my_tag 123 "abcd" book.title warning=message profile=user.profile %}
模板包含标签inclusion_tag
可以通过自定义包含标签来渲染html。
假设现在有一个需求,是要在文章详情页面中,显示所有相关评论的发布时间。因此在 my_filter_and_tags.py
中写入:
@register.inclusion_tag('article/tag_list.html') def show_comments_pub_time(article): """显示文章评论的发布时间""" comments = article.comments.all() # 把comments渲染金tag_list.html自定义包含模板中 return {'comments': comments}
templates/article/tag_list.html:
<ul> {% for comment in comments %} <li> {{ comment.created }} </li> {% endfor %} </ul>
然后在文章详情页面的模板中,随便找一个位置写入:
templates/article/detail.html
{% show_comments_pub_time article %} # 渲染
新详情页面,顺利的话就能看到所有评论的发表时间都展示出来了。
包含标签的另一个应用场景就是各种按钮了。有的按钮看上去长得都差不多,但是根据页面不同会有不同的功能,这时候也可以用包含标签来实现。
总之,包含标签可以将常用的模板代码打包成小组件,方便重复利用。