“标签”是做者从文章中提取的核心词汇,其余用户能够经过标签快速了解文章的关注点。每一篇文章的标签可能都不同,而且还可能拥有多个标签,这是与栏目功能不一样的。html
好在标签功能也有优秀的三方库:Django-taggit,免得本身动手设计了。快速开发就是这样,能“借用”就不要本身重复劳动。python
首先在虚拟环境中安装Django-taggit:git
pip install django-taggit
复制代码
安装成功后,修改项目设置以添加库:github
my_blog/settings.py
...
INSTALLED_APPS = [
...
'taggit',
]
...
复制代码
标签是文章Model的属性,所以须要修改文章模型。django
须要注意的是标签引用的不是内置字段,而是库中的TaggableManager
,它是处理多对多关系的管理器:bootstrap
article/models.py
...
# Django-taggit
from taggit.managers import TaggableManager
...
class ArticlePost(models.Model):
...
# 文章标签
tags = TaggableManager(blank=True)
...
复制代码
而后记得数据迁移。bash
修改文章的表单类,让其可以提交标签字段:服务器
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()
才能正确的保存标签,就像普通的多对多关系同样。post
最后就是在发表文章的模板中添加标签的表单项了:
templates/article/create.html
...
<!-- 提交文章的表单 -->
<form method="post" action=".">
...
<!-- 文章标签 -->
<div class="form-group">
<label for="tags">标签</label>
<input type="text" class="form-control col-3" id="tags" name="tags" >
</div>
...
</form>
...
复制代码
运行服务器,就能够在发表页面看到效果了:
多个标签最好用英文逗号进行分隔。中文逗号有的版本会报错,干脆就不要去使用了。
虽然保存标签的功能已经实现了,还得把它显示出来才行。
显示标签最经常使用的位置是在文章列表中,方便用户筛选感兴趣的文章。
修改文章列表的模板,将标签显示出来:
templates/article/list.html
...
<!-- 栏目 -->
...
<!-- 标签 -->
<span>
{% for tag in article.tags.all %}
<a href="#" class="badge badge-secondary" >
{{ tag }}
</a>
{% endfor %}
</span>
...
复制代码
连接中的class
中是Bootstrap定义的徽章样式。
插入位置紧靠在栏目按钮的后面。固然你想放到其余位置也是彻底能够的。
刷新列表页面看看效果:
有时候用户想搜索带有某一个标签的全部文章,如今就来作这个功能。
与搜索功能同样,只须要调取数据时用filter()
方法过滤结果就能够了。
修改<a>
标签中的href
,使其带有tag
参数返回到View中:
templates/article/list.html
...
<!-- 标签 -->
<span>
{% for tag in article.tags.all %}
<a href="{% url 'article:article_list' %}?tag={{ tag }}" class="badge badge-secondary" >
{{ tag }}
</a>
{% endfor %}
</span>
...
复制代码
而后在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
...
<!-- 全部相似地方加上 tag 参数,如排序、翻页等 -->
<a href="{% url 'article:article_list' %}?search={{ search }}&column={{ column }}&tag={{ tag }}">
最新
</a>
...
<a href="{% url 'article:article_list' %}?order=total_views&search={{ search }}&column={{ column }}&tag={{ tag }}">
最热
</a>
...
<a href="?page=1&order={{ order }}&search={{ search }}&column={{ column }}&tag={{ tag }}" class="btn btn-success">
« 1
</a>
<!-- 上面3条是举例,其余相似地方也请补充进去 -->
...
复制代码
标签过滤功能就完成了。
Django-taggit更多的用法请阅读官方文档:Django-taggit
本章学习了使用Django-taggit来完成标签功能。
在学习阶段,你能够不借助他人的轮子,本身实现功能:瞎折腾对掌握基础有很大帮助。
实际开发时,又分为两种状况:
到底如何选择,就根据你的喜欢进行斟酌了。