首页 > 解决方案 > Django-taggit如何修改不同用户添加相同的标签

问题描述

我正在尝试修改django-taggit以允许不同的团队添加相同的标签。

我已经修改了模型,django-taggit以便在用户向表中添加新标签时添加值。这也将 值添加到表中。userteam_idtaggig_taguserteam_idtaggit_taggeditems

目标是允许团队编辑或删除他们自己的标签,这不应该影响其他团队,因此不同的团队需要有自己独立的标签集。

在我修改的场景中,标签name和标签team_id构成了不同的标签。我希望我可以在测试不同标签之前测试team_id或将其连接到标签。但看不出 那在哪里。namedjango-taggitdjango-taggit

问题:它在django-taggit代码的哪里寻找重复的标签值?

`apps.py`
`forms.py`
`managers.py`
`models.py`
`utils.py`
`views.py`

我修改后django-taggit的模型代码如下。

from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import IntegrityError, models, router, transaction
from django.utils.text import slugify
from django.utils.translation import gettext, gettext_lazy as _
from django.conf import settings
### MODIFICATION: added django CRUM to get request user
from crum import get_current_user


try:
    from unidecode import unidecode
except ImportError:

    def unidecode(tag):
        return tag


class TagBase(models.Model):
    ### MODIFICATION: added team and user to model, removed unique=True
    name = models.CharField(verbose_name=_("Name"), max_length=100)
    slug = models.SlugField(verbose_name=_("Slug"), max_length=100)
    team_id = models.CharField(max_length=10, blank=False, null=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, 
       on_delete=models.DO_NOTHING)

    def __str__(self):
        return self.name

    def __gt__(self, other):
        return self.name.lower() > other.name.lower()

    def __lt__(self, other):
        return self.name.lower() < other.name.lower()

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        ### MODIFICATION: added team and user to taggit_taggeditem model
        ### get request user with django CRUM get_current_user()
        self.user = get_current_user()
        self.team_id = get_current_user().team_id

        if self._state.adding and not self.slug:
            self.slug = self.slugify(self.name)
            using = kwargs.get("using") or router.db_for_write(
                type(self), instance=self
            )
            # Make sure we write to the same db for all attempted writes,
            # with a multi-master setup, theoretically we could try to
            # write and rollback on different DBs
            kwargs["using"] = using
            # Be oportunistic and try to save the tag, this should work for
            # most cases ;)
            ### MODIFICATION: remove IntegrityError try/except for unique 
               which is removed
            #try:
            with transaction.atomic(using=using):
                res = super().save(*args, **kwargs)
            return res
            #except IntegrityError: 
            #    pass
            ### MODIFICATION: remove slugs create as no longer checking for 
               duplicate slugs
            # Now try to find existing slugs with similar names
            #slugs = set(
            #    self.__class__._default_manager.filter(
            #        slug__startswith=self.slug
            #    ).values_list("slug", flat=True)
            #)
            i = 1
            #while True:
            #    slug = self.slugify(self.name, i)
            #    if slug not in slugs:
            #       self.slug = slug
            #        # We purposely ignore concurrecny issues here for now.
            #       # (That is, till we found a nice solution...)
            #        return super().save(*args, **kwargs)
            #    i += 1
            while True:
                slug = self.slugify(self.name, i)
                #if slug not in slugs:
                self.slug = slug
                # We purposely ignore concurrecny issues here for now.
                # (That is, till we found a nice solution...)
                return super().save(*args, **kwargs)
                i += 1
        else:
            return super().save(*args, **kwargs)

    def slugify(self, tag, i=None):
        slug = slugify(unidecode(tag))
        if i is not None:
            slug += "_%d" % i
        return slug


class Tag(TagBase):
    class Meta:
        verbose_name = _("Tag")
        verbose_name_plural = _("Tags")
        app_label = "taggit"


class ItemBase(models.Model):
    def __str__(self):
        return gettext("%(object)s tagged with %(tag)s") % {
            "object": self.content_object,
            "tag": self.tag,
        }

    class Meta:
        abstract = True

    @classmethod
    def tag_model(cls):
        field = cls._meta.get_field("tag")
        return field.remote_field.model

    @classmethod
    def tag_relname(cls):
        field = cls._meta.get_field("tag")
        return field.remote_field.related_name

    @classmethod
    def lookup_kwargs(cls, instance):
        return {"content_object": instance}


class TaggedItemBase(ItemBase):
    tag = models.ForeignKey(
        Tag, related_name="%(app_label)s_%(class)s_items", 
           on_delete=models.CASCADE
    )

    class Meta:
        abstract = True

    @classmethod
    def tags_for(cls, model, instance=None, **extra_filters):
        kwargs = extra_filters or {}
        if instance is not None:
            kwargs.update({"%s__content_object" % cls.tag_relname(): 
               instance})
            return cls.tag_model().objects.filter(**kwargs)
        kwargs.update({"%s__content_object__isnull" % cls.tag_relname(): 
           False})
        return cls.tag_model().objects.filter(**kwargs).distinct()


class CommonGenericTaggedItemBase(ItemBase):
    content_type = models.ForeignKey(
        ContentType,
        on_delete=models.CASCADE,
        verbose_name=_("Content type"),
        related_name="%(app_label)s_%(class)s_tagged_items",
    )
    content_object = GenericForeignKey()
    ### MODIFICATION: added team and user to taggit_taggeditem model
    team_id = models.CharField(max_length=10, blank=False, null=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, 
        on_delete=models.DO_NOTHING)

    class Meta:
        abstract = True

    @classmethod
    def lookup_kwargs(cls, instance):
        return {
            "object_id": instance.pk,
            "content_type": ContentType.objects.get_for_model(instance),
            ### MODIFICATION: added team and user to taggit_taggeditem model
            "user": get_current_user(),
            "team_id": get_current_user().team_id,
        }

    @classmethod
    def tags_for(cls, model, instance=None, **extra_filters):
        tag_relname = cls.tag_relname()
        kwargs = {
            "%s__content_type__app_label" % tag_relname: 
                model._meta.app_label,
            "%s__content_type__model" % tag_relname: model._meta.model_name,
        }
        if instance is not None:
            kwargs["%s__object_id" % tag_relname] = instance.pk
        if extra_filters:
            kwargs.update(extra_filters)
        return cls.tag_model().objects.filter(**kwargs).distinct()


class GenericTaggedItemBase(CommonGenericTaggedItemBase):
    object_id = models.IntegerField(verbose_name=_("Object id"), 
        db_index=True)

    class Meta:
        abstract = True


class GenericUUIDTaggedItemBase(CommonGenericTaggedItemBase):
    object_id = models.UUIDField(verbose_name=_("Object id"), db_index=True)

    class Meta:
        abstract = True


class TaggedItem(GenericTaggedItemBase, TaggedItemBase):
    class Meta:
        verbose_name = _("Tagged Item")
        verbose_name_plural = _("Tagged Items")
        app_label = "taggit"
        ### MODIFICATION: added team_id and user to taggit_taggeditems table 
           constraints
        index_together = [["content_type", "object_id", "team_id", "user"]]
        unique_together = [["content_type", "object_id", "tag", "team_id", 
           "user"]]

标签: djangopython-3.xdjango-taggit

解决方案


推荐阅读