table of contents only for custom PDF (for now)
[wolnelektury.git] / src / newtagging / models.py
index 694f5b8..b90ea8e 100644 (file)
@@ -3,19 +3,16 @@
 Models and managers for generic tagging.
 """
 
-from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.models import ContentType
 from django.db import connection, models
-from django.utils.translation import ugettext_lazy as _
 from django.db.models.base import ModelBase
-from django.core.exceptions import ObjectDoesNotExist
 from django.dispatch import Signal
 
 qn = connection.ops.quote_name
 
-
 tags_updated = Signal(providing_args=["affected_tags"])
 
+
 def get_queryset_and_model(queryset_or_model):
     """
     Given a ``QuerySet`` or a ``Model``, returns a two-tuple of
@@ -27,7 +24,7 @@ def get_queryset_and_model(queryset_or_model):
     try:
         return queryset_or_model, queryset_or_model.model
     except AttributeError:
-        return queryset_or_model._default_manager.all(), queryset_or_model
+        return queryset_or_model.objects.all(), queryset_or_model
 
 
 ############
@@ -58,18 +55,19 @@ class TagManager(models.Manager):
         updated_tags = self.model.get_tag_list(tags)
 
         # Remove tags which no longer apply
-        tags_for_removal = [tag for tag in current_tags \
-                            if tag not in updated_tags]
+        tags_for_removal = [tag for tag in current_tags if tag not in updated_tags]
         if len(tags_for_removal):
-            self.intermediary_table_model._default_manager.filter(content_type__pk=content_type.pk,
-                                               object_id=obj.pk,
-                                               tag__in=tags_for_removal).delete()
+            self.intermediary_table_model.objects.filter(
+                content_type__pk=content_type.pk,
+                object_id=obj.pk,
+                tag__in=tags_for_removal).delete()
         # Add new tags
-        tags_to_add = [tag for tag in updated_tags
-                       if tag not in current_tags]
+        tags_to_add = [tag for tag in updated_tags if tag not in current_tags]
         for tag in tags_to_add:
-            if tag not in current_tags:
-                self.intermediary_table_model._default_manager.create(tag=tag, content_object=obj)
+            existing = self.intermediary_table_model.objects.filter(
+                content_type__pk=content_type.pk, object_id=obj.pk, tag=tag)
+            if not existing:
+                self.intermediary_table_model.objects.create(tag=tag, content_object=obj)
 
         tags_updated.send(sender=type(obj), instance=obj, affected_tags=tags_to_add + tags_for_removal)
 
@@ -78,8 +76,18 @@ class TagManager(models.Manager):
         Remove tag from an object.
         """
         content_type = ContentType.objects.get_for_model(obj)
-        self.intermediary_table_model._default_manager.filter(content_type__pk=content_type.pk,
-            object_id=obj.pk, tag=tag).delete()
+        self.intermediary_table_model.objects.filter(
+            content_type__pk=content_type.pk, object_id=obj.pk, tag=tag).delete()
+
+    def add_tag(self, obj, tag):
+        """
+        Add tag to an object.
+        """
+        content_type = ContentType.objects.get_for_model(obj)
+        relations = self.intermediary_table_model.objects.filter(
+            content_type__pk=content_type.pk, object_id=obj.pk, tag=tag)
+        if not relations:
+            self.intermediary_table_model.objects.create(tag=tag, content_object=obj)
 
     def get_for_object(self, obj):
         """
@@ -105,9 +113,10 @@ class TagManager(models.Manager):
         ``filters`` argument.
         """
         # TODO: Do we really need this filters stuff?
-        if filters is None: filters = {}
+        if filters is None:
+            filters = {}
 
-        queryset = model._default_manager.filter()
+        queryset = model.objects.filter()
         for f in filters.items():
             queryset.query.add_filter(f)
         usage = self.usage_for_queryset(queryset, counts)
@@ -122,10 +131,9 @@ class TagManager(models.Manager):
         each tag, indicating how many times it has been used against
         the Model class in question.
         """
-        usage = self.model._default_manager.filter(
+        usage = self.model.objects.filter(
             items__content_type=ContentType.objects.get_for_model(queryset.model),
-            items__object_id__in=queryset
-            )
+            items__object_id__in=queryset)
         if counts:
             usage = usage.annotate(count=models.Count('id'))
         else:
@@ -197,42 +205,13 @@ class TaggedItemManager(models.Manager):
 ##########
 # Models #
 ##########
-def create_intermediary_table_model(model):
-    """Create an intermediary table model for the specific tag model"""
-    name = model.__name__ + 'Relation'
-
-    class Meta:
-        db_table = '%s_relation' % model._meta.db_table
-        unique_together = (('tag', 'content_type', 'object_id'),)
-        app_label = model._meta.app_label
-
-    def obj_unicode(self):
-        try:
-            return u'%s [%s]' % (self.content_type.get_object_for_this_type(pk=self.object_id), self.tag)
-        except ObjectDoesNotExist:
-            return u'<deleted> [%s]' % self.tag
-
-    # Set up a dictionary to simulate declarations within a class
-    attrs = {
-        '__module__': model.__module__,
-        'Meta': Meta,
-        'tag': models.ForeignKey(model, verbose_name=_('tag'), related_name='items'),
-        'content_type': models.ForeignKey(ContentType, verbose_name=_('content type')),
-        'object_id': models.PositiveIntegerField(_('object id'), db_index=True),
-        'content_object': GenericForeignKey('content_type', 'object_id'),
-        '__unicode__': obj_unicode,
-    }
-
-    return type(name, (models.Model,), attrs)
-
 
 class TagMeta(ModelBase):
-    "Metaclass for tag models (models inheriting from TagBase)."
+    """Metaclass for tag models (models inheriting from TagBase)."""
     def __new__(mcs, name, bases, attrs):
         model = super(TagMeta, mcs).__new__(mcs, name, bases, attrs)
         if not model._meta.abstract:
-            # Create an intermediary table and register custom managers for concrete models
-            model.intermediary_table_model = create_intermediary_table_model(model)
+            # Register custom managers for concrete models
             TagManager(model.intermediary_table_model).contribute_to_class(model, 'objects')
             TaggedItemManager(model).contribute_to_class(model.intermediary_table_model, 'objects')
         return model
@@ -256,4 +235,3 @@ class TagBase(models.Model):
             return [tag_list]
         else:
             return tag_list
-