python搭建博客文章_Django搭建个人博客:文章标签功能
核心词汇来自文章的作者。其他用户可凭借标签迅速掌握文章的重点内容。一篇文通常会有独特的标签,并时常包含多个相关关键词。这个特点区别于栏目功能并不存在于此。
得益于标签功能提供的高度优化第三方库Django-taggit的存在,在项目中开发者无需自行设计标签系统
安装及设置
首先在虚拟环境中安装Django-taggit:
pip install django-taggit
安装成功后,修改项目设置以添加库:
my_blog/settings.py
...
INSTALLED_APPS = [
...
'taggit',
]
...
修改文章模型
标签是文章Model的属性,因此需要修改文章模型。
必须注意的是,在标签引用时并非使用内置字段,而是来自库中的TaggableManager对象。该对象被设计为处理复杂的多对多关系。
article/models.py
...
Django-taggit
from taggit.managers import TaggableManager
...
class ArticlePost(models.Model):
...
文章标签
tags = TaggableManager(blank=True)
...
然后记得数据迁移。
带标签文章的发表
修改文章的表单类,让其能够提交标签字段:
article/forms.py
...
class ArticlePostForm(forms.ModelForm):
class Meta:
...
fields = ('title', 'body', 'tags')
然后修改发表文章的视图,保存POST中的标签:
article/views.py
...
def article_create(request):
已有代码
if request.method == "POST":
article_post_form = ArticlePostForm(data=request.POST)
if article_post_form.is_valid():
new_article = article_post_form.save(commit=False)
...
new_article.save()
新增代码,保存 tags 的多对多关系
article_post_form.save_m2m()
...
特别需要注意的是,在表单设置为commit=False选项的情况下,则必须确保通过调用save_m2m()来正确保存标签,并与传统的双向多对多关系处理方式相似。
最后就是在发表文章的模板中添加标签的表单项了:
templates/article/create.html
...
...
标签
class="form-control col-3"
id="tags"
name="tags"
...
...
运行服务器,就可以在发表页面看到效果了:

建议将多个标签以英文逗号的形式分隔开来;对于使用中文逗号的版本而言,在某些情况下可能会导致错误信息显示不出来;因此建议避免使用中文逗号来标注标签
列表中显示标签
虽然保存标签的功能已经实现了,还得把它显示出来才行。
显示标签最常用的位置是在文章列表中,方便用户筛选感兴趣的文章。
修改文章列表的模板,将标签显示出来:
templates/article/list.html
...
...
{% for tag in article.tags.all %}
class="badge badge-secondary"
{{ tag }}
{% endfor %}
...
链接中的class中是Bootstrap定义的徽章样式。
栏目按钮是插入位置的邻近项;当然你可以将其放置在其他地方。
刷新列表页面看看效果:

标签过滤
有时候用户想搜索带有某一个标签的所有文章,现在就来做这个功能。
与搜索功能一样,只需要调取数据时用filter()方法过滤结果就可以了。
修改标签中的href,使其带有tag参数返回到View中:
templates/article/list.html
...
{% for tag in article.tags.all %}
{% endfor %}
...
然后在View中取得tag的值,并进行搜索。
这段代码实现了article_list()函数的全面编写(特别包含上一章末尾未涉及栏目查询的部分),以便于读者进行对比参考。
article/views.py
...
def article_list(request):
从 url 中提取查询参数
search = request.GET.get('search')
order = request.GET.get('order')
column = request.GET.get('column')
tag = request.GET.get('tag')
初始化查询集
article_list = ArticlePost.objects.all()
搜索查询集
if search:
article_list = article_list.filter(
Q(title__icontains=search) |
Q(body__icontains=search)
)
else:
search = ''
栏目查询集
if column is not None and column.isdigit():
article_list = article_list.filter(column=column)
标签查询集
if tag and tag != 'None':
article_list = article_list.filter(tags__name__in=[tag])
查询集排序
if order == 'total_views':
article_list = article_list.order_by('-total_views')
paginator = Paginator(article_list, 3)
page = request.GET.get('page')
articles = paginator.get_page(page)
需要传递给模板(templates)的对象
context = {
'articles': articles,
'order': order,
'search': search,
'column': column,
'tag': tag,
}
return render(request, 'article/list.html', context)
...
请特别注意,在 Django-taggit 框标中标签过滤的方式是 filter(tags__name__in=[tag])。具体而言,在 tags 字段内筛选 name 为 tag 的数据条目。将赋值给变量 tag 时需使用方括号包裹。
之所以这样写是因为Django-taggit还支持多标签的联合查询,比如:
Model.objects.filter(tags__name__in=["tag1", "tag2"])
为了实现带参数的交叉查询,还要将翻页等位置的href修改一下:
templates/article/list.html
...
最新
...
最热
...
« 1
...
标签过滤功能就完成了。
Django-taggit更多的用法请阅读官方文档:Django-taggit
总结
本章学习了使用Django-taggit来完成标签功能。
在学习阶段无需借鉴他人经验就能自主开发功能:通过摸爬滚打显著促进基础掌握。
实际开发时,又分为两种情况:
表面需求中的一项通用功能,在完成开发后带来的改动微乎其微:此类功能建议尽可能地采用模块化设计以提高开发效率。时光荏苒、稍纵即逝的碎片时间不容浪费。
项目需求中要求实现大量高度定制的功能,在投入运营后仍需不断修改。这类功能由于频繁修改底层代码容易出错,并非建议在现成的开源项目中反复修复;与其耗时耗力地逐步优化现有代码库不如直接从零开始编写。
到底如何选择,就根据你的喜欢进行斟酌了。
有疑问请在杜赛的个人网站留言,我会尽快回复。
或Email私信我:dusaiphoto@foxmail.com
