我正在尝试修改django-taggit
,以允许由单独的团队添加相同的标签。
我已经修改了django-taggit
模型,以便在用户向user
表中添加新标签时添加了team_id
和taggig_tag
值。这还会将user
和team_id
的值添加到taggit_taggeditems
表中。
目标是允许团队编辑或删除自己的标签,并且这不会影响其他团队,因此不同的团队需要拥有自己的单独标签集。
在我的修改方案中,标签name
和team_id
构成了不同的标签。我希望在team_id
测试不同的标签之前,我可以测试name
或将其连接到标签django-taggit
。但是看不到django-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"]]