summaryrefslogtreecommitdiff
path: root/lib/taggit/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/taggit/models.py')
-rw-r--r--lib/taggit/models.py160
1 files changed, 160 insertions, 0 deletions
diff --git a/lib/taggit/models.py b/lib/taggit/models.py
new file mode 100644
index 0000000..d8a0a41
--- /dev/null
+++ b/lib/taggit/models.py
@@ -0,0 +1,160 @@
+import django
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes.generic import GenericForeignKey
+from django.db import models, IntegrityError, transaction
+from django.template.defaultfilters import slugify as default_slugify
+from django.utils.translation import ugettext_lazy as _, ugettext
+
+
+class TagBase(models.Model):
+ name = models.CharField(verbose_name=_('Name'), max_length=100)
+ slug = models.SlugField(verbose_name=_('Slug'), unique=True, max_length=100)
+
+ def __unicode__(self):
+ return self.name
+
+ class Meta:
+ abstract = True
+
+ def save(self, *args, **kwargs):
+ if not self.pk and not self.slug:
+ self.slug = self.slugify(self.name)
+ if django.VERSION >= (1, 2):
+ from django.db import router
+ 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
+ trans_kwargs = {"using": using}
+ else:
+ trans_kwargs = {}
+ i = 0
+ while True:
+ i += 1
+ try:
+ sid = transaction.savepoint(**trans_kwargs)
+ res = super(TagBase, self).save(*args, **kwargs)
+ transaction.savepoint_commit(sid, **trans_kwargs)
+ return res
+ except IntegrityError:
+ transaction.savepoint_rollback(sid, **trans_kwargs)
+ self.slug = self.slugify(self.name, i)
+ else:
+ return super(TagBase, self).save(*args, **kwargs)
+
+ def slugify(self, tag, i=None):
+ slug = default_slugify(tag)
+ if i is not None:
+ slug += "_%d" % i
+ return slug
+
+
+class Tag(TagBase):
+ class Meta:
+ verbose_name = _("Tag")
+ verbose_name_plural = _("Tags")
+
+
+
+class ItemBase(models.Model):
+ def __unicode__(self):
+ return ugettext("%(object)s tagged with %(tag)s") % {
+ "object": self.content_object,
+ "tag": self.tag
+ }
+
+ class Meta:
+ abstract = True
+
+ @classmethod
+ def tag_model(cls):
+ return cls._meta.get_field_by_name("tag")[0].rel.to
+
+ @classmethod
+ def tag_relname(cls):
+ return cls._meta.get_field_by_name('tag')[0].rel.related_name
+
+ @classmethod
+ def lookup_kwargs(cls, instance):
+ return {
+ 'content_object': instance
+ }
+
+ @classmethod
+ def bulk_lookup_kwargs(cls, instances):
+ return {
+ "content_object__in": instances,
+ }
+
+
+class TaggedItemBase(ItemBase):
+ if django.VERSION < (1, 2):
+ tag = models.ForeignKey(Tag, related_name="%(class)s_items")
+ else:
+ tag = models.ForeignKey(Tag, related_name="%(app_label)s_%(class)s_items")
+
+ class Meta:
+ abstract = True
+
+ @classmethod
+ def tags_for(cls, model, instance=None):
+ if instance is not None:
+ return cls.tag_model().objects.filter(**{
+ '%s__content_object' % cls.tag_relname(): instance
+ })
+ return cls.tag_model().objects.filter(**{
+ '%s__content_object__isnull' % cls.tag_relname(): False
+ }).distinct()
+
+
+class GenericTaggedItemBase(ItemBase):
+ object_id = models.IntegerField(verbose_name=_('Object id'), db_index=True)
+ if django.VERSION < (1, 2):
+ content_type = models.ForeignKey(
+ ContentType,
+ verbose_name=_('Content type'),
+ related_name="%(class)s_tagged_items"
+ )
+ else:
+ content_type = models.ForeignKey(
+ ContentType,
+ verbose_name=_('Content type'),
+ related_name="%(app_label)s_%(class)s_tagged_items"
+ )
+ content_object = GenericForeignKey()
+
+ class Meta:
+ abstract=True
+
+ @classmethod
+ def lookup_kwargs(cls, instance):
+ return {
+ 'object_id': instance.pk,
+ 'content_type': ContentType.objects.get_for_model(instance)
+ }
+
+ @classmethod
+ def bulk_lookup_kwargs(cls, instances):
+ # TODO: instances[0], can we assume there are instances.
+ return {
+ "object_id__in": [instance.pk for instance in instances],
+ "content_type": ContentType.objects.get_for_model(instances[0]),
+ }
+
+ @classmethod
+ def tags_for(cls, model, instance=None):
+ ct = ContentType.objects.get_for_model(model)
+ kwargs = {
+ "%s__content_type" % cls.tag_relname(): ct
+ }
+ if instance is not None:
+ kwargs["%s__object_id" % cls.tag_relname()] = instance.pk
+ return cls.tag_model().objects.filter(**kwargs).distinct()
+
+
+class TaggedItem(GenericTaggedItemBase, TaggedItemBase):
+ class Meta:
+ verbose_name = _("Tagged Item")
+ verbose_name_plural = _("Tagged Items")