使用django-taggit打造自己的标签系统

介绍

django-taggit是一个通用的,易用的标签系统,有了它以后,我们可以轻松地给任何模型打标签,并能很方便的对标签进行管理。
安装:

pip install django-taggit

使用方法

  1. 注册django-taggit应用
INSTALLED_APPS = [
...
'taggit',
...
]
  1. 在model中添加TaggableManager字段
from django.db import models

from taggit.managers import TaggableManager

class Food(models.Model):
    # ... fields here

    tags = TaggableManager()
  1. 后台添加标签以及查询方法

>>> apple = Food.objects.create(name="apple")
# 添加标签
>>> apple.tags.add("red", "green", "delicious")

# 查看单签对象标签
>>> apple.tags.all()
[<Tag: red>, <Tag: green>, <Tag: delicious>]

# 删除对象的某个标签
>>> apple.tags.remove("green")
>>> apple.tags.all()
[<Tag: red>, <Tag: delicious>]

# 设置标签,已有标签会被清理掉。
>>> apple.tags.set('red','big')

# 查询包含某一标签的食物
>>> Food.objects.filter(tags__name__in=["red"])
[<Food: apple>, <Food: cherry>]
  1. 当主键为UUID时,如何处理?
# 定义UUID的TaggedItem,用于保存
class UUIDTaggedItem(GenericTaggedItemBase, TaggedItemBase):
    class Meta:
        verbose_name = "UUID标签项"
        verbose_name_plural = verbose_name
        index_together = [["content_type", "object_id"]]
        unique_together = [["content_type", "object_id", "tag"]]

# 实例化TaggbleManager是通过through参数传入UUIDTaggedItem ,替换原来的TaggedItem
tags = TaggableManager(blank=True,through=UUIDTaggedItem)

DRF中的使用

如何搜索

解决思路:在查询方法中,添加tags字段的查询处理逻辑,实现查询。
生产环境中,除了当前模型有标签外,可能在某些外键中也包含标签。那么考虑重写ModelViewSet的get_search_factor()方法[注:该方法来自自定义的GenericAPIView],添加对tags字段的支持,代码如下:

from django.db.models import Q

tag_fields = [] # 存放包含tags的列,可能是tags也可能是外键。

def get_search_factor(self,search_filter, contain_filter=True, regex=True):
    ...
    if 'tags' in search_filter:
        search_filter_tags = self.get_tags_search_filter(search_filter['tags'])
        del search_filter['tags']
    ...

def get_tags_search_filter(self, tag_str):
    """
    获取tags字段的查询条件,可能有多个tags列,由tag_fields决定。
    :params tag_str: 可以有多个tag,用英文逗号(,)隔开
    :return:
    """
    search_filter_tags = None
    tag_list = tag_str.split(',')
    for tag_field in self.tag_fields:
        if not search_filter_tags :
                search_filter_tags = Q()
                search_filter_tags.connector = 'OR'
        if tag_field == 'tags':
            search_filter_tags.children.append(('tags__name__in', tag_list))
        else:
            search_filter_tags.children.append(('%s__tags__name__in' % tag_field, tag_list))
            
    return search_filter_tags
                

如何展示

# 自定义TagSerializerField,将多个tag用英文逗号隔开。
class TagSerializerField(serializers.Field):

    def __init__(self, **kwargs):
        # 默认只读
        kwargs['read_only'] = True
        super().__init__(**kwargs)
        

    def to_representation(self, data):
        return ','.join(data.values_list('name', flat=True))
    
    def to_internal_value(self, data):
        return None

# 序列化器使用该字段。
class TagSerializer(serializers.ModelSerializer):
    tags = TagSerializerField()

如何通过API保存标签

# 请求时,多个标签用英文逗号(,)隔开
{
    ...
    "tags":"中心合同,2020"   
    ...
}


# 在perform_create处理新增, perform_update处理更新。

def perform_create(self, serializer):
    instance = serializer.save()
    if 'tags' in self.request.DATA:
        instance.tags.set(*self.request.DATA['tags'].split(','))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值