一、问题描述
django-taggit是一个很好的给文章打标签的应用,但是它的模型存储的标签默认是只支持ascii的slug,不支持中文。为了让其支持中文,我们不能直接使用Tag模型类,而是应该自定义模型类。当然,这个自定义并不是从零开始,而是继承它提供的基类。
二、代码实现
说明:下面的基于Django3 by Example里的博客项目,但是我没有把全部代码写全,只写了我实现的自定义taggit模型类支持中文的部分。对此项目感兴趣的朋友可以自行阅读书籍。
models.py
from taggit.managers import TaggableManager
from taggit.models import TagBase,GenericTaggedItemBase
from django.utils.text import slugify
from django.utils.translation import gettext, gettext_lazy as _
class MyTag(TagBase):
# 这一步是关键,要设置allow_unicode=True,这样这个字段才能支持中文
slug = models.SlugField(verbose_name=_("slug"), unique=True, max_length=100,allow_unicode=True)
# 这个方法也是要覆盖的,它是用来计算slug的,也是添加allow_unicode=True参数
def slugify(self, tag, i=None):
slug = slugify(tag,allow_unicode=True)
if i is not None:
slug += "_%d" % i
return slug
class Meta:
verbose_name = _("tag")
verbose_name_plural = _("tags")
app_label = "taggit"
class TaggedWhatever(GenericTaggedItemBase):
# 把我们自定义的模型类传进来,它就能知道如何处理
tag = models.ForeignKey(
MyTag,
on_delete=models.CASCADE,
related_name="%(app_label)s_%(class)s_items",
)
class Post(models.Model):
'''这是我们自己的博客文章模型类'''
# 它的字段全省略了
# ......
# 声明这个manager也是基于我们自定义的模型类
tags = TaggableManager(through=TaggedWhatever)
注意:定义了模型类之后要记得迁移数据库
views.py
from .models import Post,MyTag
def post_list(request,tag_slug=None):
posts = Post.published.all()
tag = None
if tag_slug:
# 从MyTag对应的数据库表里查询tag
tag = get_object_or_404(MyTag,slug=tag_slug)
# 因为文章和标签是多对多的关系,所以这里要把tag放到列表里面
# 这里的意思是查询那些文章标签里包含给定标签的文章
posts = object_list.filter(tags__in=[tag])
return render(request,
'blog/post/list.html',
{'posts':posts,
'tag':tag})
urls.py(这是blog这个app自己的urls,不是总的UrlConf)
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
# 下面的两个路由对应同一个视图
# 如果没有标签,就是第一个路由
# 提供了标签,就是第二个路由
path('',views.post_list,name='post_list'),
# 这里的参数类型不要写slug,否则又会忽视中文,写str就行了
path('tag/<str:tag_slug>/',
views.post_list,
name='post_list_by_tag')
]
下面的屏幕截图是我选择了“娱乐”这个标签之后,两篇有“娱乐”标签的博客文章就被筛选出来了: