Django本身附带的模板系统提供了大量的内建标签和过滤器供我们在开发的时候使用。这些标签和过滤器涵盖了Django Web开发过程中常见的各种模板处理场景,但是如果你的需求有一些特殊,或者由于种种原因,内建的标签和过滤器满足不了项目的功能需要,那么可能就需要自定义标签和过滤器。
关于如何自定义Django模板标签和过滤器,在Django的官方文档上有比较详细的介绍,但是缺少足够清晰的实例说明,所以本篇文章将以开源文档写作应用——MrDoc的源码,来演示讲解自定义Django的模板过滤器。
一、问题产生
在MrDoc中,文档的模型结构中包含了如下字段:
- name:表示文档的标题;
- pre_content:表示编辑的Markdown文档内容;
- content:表示生成的HTML文档内容;
- parent_doc:表示上级文档的ID,若没有上级文档,则为0;
- top_doc:表示所属文集的ID;
- sort:表示排序顺序;
- create_user:表示创建人;
- create_time:表示创建时间;
- modify_time:表示修改时间;
其模型代码如下所示:
# 文档模型
class Doc(models.Model):
name = models.CharField(verbose_name="文档标题",max_length=50)
pre_content = models.TextField(verbose_name="编辑内容")
content = models.TextField(verbose_name="文档内容")
parent_doc = models.IntegerField(default=0,verbose_name="上级文档")
top_doc = models.IntegerField(default=0,verbose_name="所属项目")
sort = models.IntegerField(verbose_name='排序',default=99)
create_user = models.ForeignKey(User,on_delete=models.CASCADE)
create_time = models.DateTimeField(auto_now_add=True)
modify_time = models.DateTimeField(auto_now=True)
具体的代码,可以在MrDoc的开源地址:https://gitee.com/zmister/MrDoc/ 进行查看。
在这里,每个文档都是通过parent_doc来获取上下层级关系,这样可以很快找到某个文档的上级文档,但是在形成层次递进的层级关系显示时,就不是很方便。因为最终,我们需要的层级结构是如下图所示那样的:
要实现上面的效果,一种方法是遍历文集下每一个文档,然后根据其parent_doc生成一个层级的JSON,最后在前端渲染成层级的目录树结构。但是这样既需要在后端视图进行逻辑判断和数据处理,又需要在前端进行渲染,稍微有点麻烦。在这种情况下,MrDoc采用的Django自定义模板过滤器的方法,来实现上述功能。
二、创建过滤器
在Django中自定义模板标签和过滤器,一共需要三步:
第一、在任意一个app下创建一个templatetags 包,也就是包含__init__.py文件的文件夹。在MrDoc中,这个文件夹创建在了app_doc下,如下图所示:
第二、在templatetags目录下继续创建一个Python文件,文件名将会作为Django模板加载的标记名称。在这里,MrDoc创建了一个名为doc_filter的Python文件作为自定义标签的加载名称,如下图所示:
第三,在相应的Python文件中编写自定义的过滤器。首先引入所需要库:
from app_doc.models import *
from django import template
然后定义一个变量register,其是template.Libbary()的实例。根据Django官方文档的说法,要让创建的文件成为有效的标签库可加载,就必须包含模块级的register变量。代码如下所示:
register = template.Library()
接着,我们创建一个函数作为过滤器的工作函数,并使用刚刚创建的register作为装饰器,将过滤器注册,代码如下所示:
# 获取文档的子文档
@register.filter(name='get_next_doc')
def get_next_doc(value):
return Doc.objects.filter(parent_doc=value).order_by('sort')
在这里,我们创建了一个名为get_next_doc()的函数,其接受一个值,我们将其设定为文档的ID,在函数中我们查询文档中上级文档ID为传入值的数据并返回。
其完整代码如下图所示:
这样,我们自定义的模板过滤器就创建好了,下一步进行调用即可。
三、调用过滤器
在文档页的视图函数中,我们会获取了文档所属文集的所有一级文档,代码如下图所示:
这个project_docs将会传递到前端模板上,我们将加载自定义的模板标签,然后通过自定义的模板过滤器get_next_doc 获取到下一级的文档信息。其代码如下图所示:
这样,我们就借助Django自定义模板过滤器,实现了前台页面上文集文档层级显示的效果了。
文章版权所有:州的先生博客,转载必须保留出处及原文链接