作者:HelloGitHub-追梦人文中涉及的示例代码已更新至HelloGitHub-Team仓库。我们博客的侧边栏中有四个项目:最新文章、档案、类别和标签云。这些内容是相对固定和独立的,会在每个页面上展示。如果像文章列表或者文章详情这样的数据是从视图函数中获取并传给模板的,那么每个页面对应的视图函数中都要写一个段落。为这些内容编写代码,这就造成了大量的重复代码。更好的方案是直接在模板中获取。为此,我们使用django的一项新技术:自定义模板标签来完成任务。使用模板标签的解决方案我们已经接触过一些Django内置的模板标签,比如比较简单的{%static%}模板标签,它可以帮助我们在模板中引入静态文件。还有更复杂的标签,例如{%for%}{%endfor%}。这里我们要自己定义一个模板标签,比如一个名为show_recent_posts的模板标签,它可以这样工作:我们只需要在模板中写{%show_recent_posts%},那么就会渲染一个最新的文章列表页面template,这个和我们写博客首页的view功能类似。在首页视图函数中,从数据库中获取文章列表并保存到post_list变量中,然后将post_list变量传递给模板。该模板使用for模板标记循环遍历文章列表变量以显示每篇文章。这里唯一的区别是我们不是在视图函数中,而是通过自定义{%show_recent_posts%}模板标签在模板中从数据库中获取文章列表。以上是解决方法,但是模板标签不是随便写的。它们必须遵循django规范才能在django模板系统中使用。下面将根据这些规范来实现我们的要求。模板标签目录结构首先在我们的博客应用下创建一个templatetags文件夹。然后在这个文件夹下创建一个__init__.py文件使这个文件夹成为一个Python包,然后在templatetags目录下创建一个blog_extras.py文件,里面存放自定义的模板标签代码。此时你的目录结构应该是这样的:blog\__init__.pyadmin.pyapps.pymigrations\__init__.pymodels.pystatic\templatetags\__init__.pyblog_extras.pytests.pyviews.pywritetemplate标签代码接下来就是编写各个模板标签的代码,自定义模板标签代码写在blog_extras.py文件中。其实一个模板标签本质上就是一个Python函数,所以按照一个Python函数的思路写模板标签的代码就可以了,并没有什么新意和新知识在里面。最新帖子模板标签打开blog_extras.py文件并开始编写我们的最新帖子模板标签。fromdjangoimporttemplatefrom..modelsimportPost,Category,Tagregister=template.Library()@register.inclusion_tag('blog/inclusions/_recent_posts.html',takes_context=True)defshow_recent_posts(context,num=5):返回{'recent_post_list':Post.objects.all().order_by('-created_time')[:num],}这里我们先导入模板模块,然后实例化一个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自身传递的模板变量)。当然,这里不使用这个上下文。这里只是一个简单的演示。如果需要使用,可以在模板标签函数的定义中使用上下文变量来引用这个上下文。下一步是定义模板_recent_posts.html的内容。在templatesblogs目录下创建一个inclusions文件夹,然后创建一个_recent_posts.html文件,内容如下:{%forpostinrecent_post_list%}
