作者:HelloGitHub-追梦人物
文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库
我们的博客侧边栏有四项内容:最新文章、归档、分类和标签云。这些内容相对比较固定和独立,且在各个页面都会显示,如果像文章列表或者文章详情一样,从视图函数中获取这些数据然后传递给模板,则每个页面对应的视图函数里都要写一段获取这些内容的代码,这会导致很多重复代码。更好的解决方案是直接在模板中获取,为此,我们使用 django 的一个新技术:自定义模板标签来完成任务。
使用模板标签的解决思路我们前面已经接触过一些 django 内置的模板标签,比如比较简单的 {% static %} 模板标签,这个标签帮助我们在模板中引入静态文件。还有比较复杂的如 {% for %} {% endfor%} 标签。这里我们希望自己定义一个模板标签,例如名为 show_recent_posts 的模板标签,它可以这样工作:我们只要在模板中写入 {% show_recent_posts %},那么模板中就会渲染一个最新文章列表页面,这和我们在编写博客首页面视图函数是类似的。首页视图函数中从数据库获取文章列表并保存到 post_list 变量,然后把这个 post_list 变量传给模板,模板使用 for 模板标签循环这个文章列表变量,从而展示一篇篇文章。这里唯一的不同是我们从数据库获取文章列表的操作不是在视图函数中进行,而是在模板中通过自定义的 {% show_recent_posts %} 模板标签进行。
以上就是解决思路,但模板标签不是随意写的,必须遵循 django 的规范才能在 django 的模板系统中使用,下面就依照这些规范来实现我们的需求。
模板标签目录结构首先在我们的 blog 应用下创建一个 templatetags 文件夹。然后在这个文件夹下创建一个 __init__.py 文件,使这个文件夹成为一个 Python 包,之后在 templatetags 目录下创建一个 blog_extras.py 文件,这个文件存放自定义的模板标签代码。
此时你的目录结构应该是这样的:
blog\ __init__.py admin.py apps.py migrations\ __init__.py models.py static\ templatetags\ __init__.py blog_extras.py tests.py views.py 编写模板标签代码接下来就是编写各个模板标签的代码了,自定义模板标签代码写在 blog_extras.py 文件中。其实模板标签本质上就是一个 Python 函数,因此按照 Python 函数的思路来编写模板标签的代码就可以了,并没有任何新奇的东西或者需要新学习的知识在里面。
最新文章模板标签打开 blog_extras.py 文件,开始写我们的最新文章模板标签。
from django import template from ..models import Post, Category, Tag register = template.Library() @register.inclusion_tag('blog/inclusions/_recent_posts.html', takes_context=True) def show_recent_posts(context, num=5): return { 'recent_post_list': Post.objects.all().order_by('-created_time')[:num], }这里我们首先导入 template 这个模块,然后实例化了一个 template.Library 类,并将函数 show_recent_posts 装饰为 register.inclusion_tag,这样就告诉 django,这个函数是我们自定义的一个类型为 inclusion_tag 的模板标签。
inclusion_tag 模板标签和视图函数的功能类似,它返回一个字典值,字典中的值将作为模板变量,传入由 inclusion_tag 装饰器第一个参数指定的模板。当我们在模板中通过 {% show_recent_posts %}使用自己定义的模板标签时,django 会将指定模板的内容使用模板标签返回的模板变量渲染后替换。
inclusion_tag 装饰器的参数 takes_context 设置为 True 时将告诉 django,在渲染 _recent_posts.html 模板时,不仅传入show_recent_posts 返回的模板变量,同时会传入父模板(即使用 {% show_recent_posts %} 模板标签的模板)上下文(可以简单理解为渲染父模板的视图函数传入父模板的模板变量以及 django 自己传入的模板变量)。当然这里并没有用到这个上下文,这里只是做个简单演示,如果需要用到,就可以在模板标签函数的定义中使用 context 变量引用这个上下文。
接下来就是定义模板 _recent_posts.html 的内容。在 templates\blogs 目录下创建一个 inclusions 文件夹,然后创建一个 _recent_posts.html 文件,内容如下:
<div> <h3>最新文章</h3> <ul> {% for post in recent_post_list %} <li> <a href="{{ post.get_absolute_url }}">{{ post.title }}</a> </li> {% empty %} 暂无文章! {% endfor %} </ul> </div>很简单,循环由 show_recent_posts 传递的模板变量 recent_post_list 即可,和 index.html 中循环显示文章列表是一样的。
归档模板标签