Commits

offline committed 93bd84c

many improvements

  • Participants
  • Parent commits ff8943e

Comments (0)

Files changed (4)

File tagging2/fields.py

 
 import settings
 from models import Tag
-from utils import edit_string_for_tags
+from utils import edit_string_for_tags, parse_tag_input
 from managers import TagManager
-from methods import tags_for_object, tags_update
+from methods import tags_for_object, tags_update, tag_list
 
 
 class TagField(CharField):
         
         setattr(cls, 'tags_for_object', tags_for_object)
         setattr(cls, 'tags_update', tags_update)
+        setattr(cls, 'tag_list', tag_list)
         
         super(TagField, self).contribute_to_class(cls, name)
 
 
            >>> l = Link.objects.get(...)
            >>> l.tags
-           'tag1 tag2 tag3'
+           'tag1, tag2, tag3'
 
            >>> Link.tags
-           'tag1 tag2 tag3 tag4'
+           'tag1, tag2, tag3, tag4'
+        
 
         """
         # Handle access on the model (i.e. Link.tags)
         """
         Helper: set an instance's tag cache.
         """
+        tags = ", ".join(parse_tag_input(tags))
         setattr(instance, '_%s_cache' % self.attname, tags)
 
     def get_internal_type(self):
         return 'CharField'
 
     def formfield(self, **kwargs):
-        from newtags import forms
+        from tagging2 import forms
         defaults = {'form_class': forms.TagField}
         defaults.update(kwargs)
         return super(TagField, self).formfield(**defaults)

File tagging2/managers.py

 
 
 class TagManager(models.Manager):
-    def _get_usage(self, queryset, counts=False, min_count=None, order=None):
+    def _get_usage(self, queryset, min_count=None, top=False):
         """
         Obtain a list of dicts with tag names and counters if counts is True
         """
-        if not order or order == 'name':
-            order = '-tag__name'
-        elif order == 'count':
-            counts = True
-            order = '-count'
         objects_id = [i.pk for i in queryset]
         ctype = ContentType.objects.get_for_model(self.model)
         qs = TaggedItem.objects.filter(content_type=ctype, object_id__in=objects_id).values('tag__name')
-        if counts:
-            qs = qs.annotate(count=Count('tag')).order_by(order)
+        qs = qs.annotate(count=Count('tag'))
+        if top:
+            qs.order_by('-count')
         tags = []
         for item in qs:
-            tag = {'name': item['tag__name']}
-            if counts:
-                tag.update({'count': item['count']})
+            tag = {'name': item['tag__name'], 'count': item['count']}
+            if min_count and min_count > item['count']:
+                continue
             tags.append(tag)
         return tags
 
 
 
-    def usage_for_model(self, counts=False, min_count=None, filters=None, order=None):
+    def usage_for_model(self, filters=None, min_count=None, top=None):
         """
         Obtain a list of all tags associated with Model excluding filtered instances.
 
-        If ``counts`` is True, a ``count`` key will be added to
-        each tag, indicating how many times it has been used against
-        the Model class in question.
-
         If ``min_count`` is given, only tags which have a ``count``
         greater than or equal to ``min_count`` will be returned.
         Passing a value for ``min_count`` implies ``counts=True``.
         of field lookups to be applied to the given Model as the
         ``filters`` argument.
         
-        ``order`` can be 'count' for popularity ordering, and 'name' (default) for
-        alphabet ordering. Passing ``order='count'`` implies ``counts=True``.
+        If ``top==True``, tags will be ordered by popularity, otherwise alphabet ordering.
         """
         
         if filters is None: 
         for filter in filters.items():
             queryset.query.add_filter(filter)
             
-        return self._get_usage(queryset, counts, min_count, order)
+        return self._get_usage(queryset, min_count, top)
 
 
-    def get_items_by_tags(self, tags):
-        ctype = ContentType.objects.get_for_model(self.model)
-        tags = get_tag_list(tags)
-        items_id_list = [tagged_item.object_id for tag in tags for tagged_item in tag.items.filter(content_type=ctype)]
-        items = self.model._default_manager.filter(pk__in=items_id_list)
-        return items
-    
 
-    def related_tags_cloud(self, tags, steps=None, counts=True, min_count=None):
-        """
-        Obtain tags cloud used in instances along with tags provided
-        
-        ``tags` - tag instances, tag primary keys or string representation of tags
-        
-        If ``counts`` is True, a ``count`` key will be added to
-        each tag, indicating how many times it has been used against
-        the Model class in question.
-        
-        """
-        items = self.get_items_by_tags(tags)
-        tags = self._get_usage(items, counts=counts)
-        return calculate_cloud(tags, steps=steps)
-        
-
-    def related_tags(self, tags, counts=False, min_count=None):
-        """
-        Obtain a list of tags related to a given list of tags - that
-        is, other tags used by items which have all the given tags.
-
-        If ``counts`` is True, a ``count`` attribute will be added to
-        each tag, indicating the number of items which have it in
-        addition to the given list of tags.
-
-        If ``min_count`` is given, only tags which have a ``count``
-        greater than or equal to ``min_count`` will be returned.
-        Passing a value for ``min_count`` implies ``counts=True``.
-        """
-        raise NotImplementedError
-
-
-    def cloud_for_model(self, steps=4, distribution=LOGARITHMIC,
-                        filters=None, min_count=None):
+    def cloud_for_model(self, steps=None, distribution=LOGARITHMIC,
+                        filters=None, min_count=None, top=False):
         """
         Obtain a list of tags associated with instances of the given
         Model, giving each tag a ``count`` attribute indicating how
 
         ``distribution`` defines the type of font size distribution
         algorithm which will be used - logarithmic or linear. It must
-        be either ``newtags.utils.LOGARITHMIC`` or
-        ``newtags.utils.LINEAR``.
+        be either ``tagging2.utils.LOGARITHMIC`` or
+        ``tagging2.utils.LINEAR``.
 
         To limit the tags displayed in the cloud to those associated
         with a subset of the Model's instances, pass a dictionary of
         ``count`` greater than or equal to ``min_count``, pass a value
         for the ``min_count`` argument.
         """
-        tags = list(self.usage_for_model(counts=True, filters=filters,
-                                         min_count=min_count))
+        tags = self.usage_for_model(filters, min_count, top)
         return calculate_cloud(tags, steps, distribution)
+
+
+    def get_items_by_tags(self, tags):
+        ctype = ContentType.objects.get_for_model(self.model)
+        tags = get_tag_list(tags)
+        items_id_list = [tagged_item.object_id for tag in tags for tagged_item in tag.items.filter(content_type=ctype)]
+        items = self.model._default_manager.filter(pk__in=items_id_list)
+        return items
     
 
+    def related_tags_cloud(self, tags, steps=None, min_count=None):
+        """
+        Obtain tags cloud used in instances along with tags provided
+        
+        ``tags` - tag instances, tag primary keys or string 
+        representation of tags    
+        """
+        items = self.get_items_by_tags(tags)
+        tags = self._get_usage(items)
+        return calculate_cloud(tags, steps=steps)
+        
+
+    def related_tags(self, tags, min_count=None, top=False):
+        """
+        Obtain a list of tags related to a given list of tags - that
+        is, other tags used by items which have all the given tags.
+
+        If ``min_count`` is given, only tags which have a ``count``
+        greater than or equal to ``min_count`` will be returned.
+        Passing a value for ``min_count`` implies ``counts=True``.
+        """
+        items = self.get_objects_with_any_tags(tags)
+        return self._get_usage(items, min_count, top)
+
+    
+    
+    def _get_tagged_items_by_tags(self, tags):
+        tags = get_tag_list(tags)
+        ctype = ContentType.objects.get_for_model(self.model)
+        tagged_items = TaggedItem.objects.filter(tag__in=tags, content_type=ctype).order_by("object_id")
+        return tagged_items
+    
     
     @cache_result
-    def get_intersection_by_model(self, tags):
+    def get_objects_with_all_tags(self, tags):
         """
         Create a ``QuerySet`` containing instances of the specified
         model associated with *all* of the given list of tags.
         """
         tags = get_tag_list(tags)
-        if not tags:
-            return self.model._default_manager.none()
+        tagged_items = self._get_tagged_items_by_tags(tags)
+
+        objects_id_list = []
         
-        ctype = ContentType.objects.get_for_model(self.model)
-        items = TaggedItem.objects.filter(tag__in=tags, content_type=ctype).order_by("object_id")
-        
-        objects_id = []
-        
-        for object_id, tag_list in groupby(items, lambda i: i.object_id):
+        for object_id, tag_list in groupby(tagged_items, lambda i: i.object_id):
             if len(list(tag_list)) == len(tags):
-                objects_id.append(object_id)
-        
-        if not objects_id:
-            return self.model._default_manager.none()
+                objects_id_list.append(object_id)
+                
+        items = self.model._default_manager.filter(pk__in=objects_id_list)
 
-        return self.model._default_manager.filter(pk__in=objects_id)
+        return items
 
 
     @cache_result
-    def get_union_by_model(self, tags):
+    def get_objects_with_any_tags(self, tags):
         """
         Create a ``QuerySet`` containing instances of the specified
         model associated with *any* of the given list of tags.
         """
-        tags = get_tag_list(tags)
-
-        if not tags:
-            return self.model._default_manager.none()
-
-        ctype = ContentType.objects.get_for_model(self.model)
-        items = TaggedItem.objects.filter(tag__in=tags, content_type=ctype).order_by("object_id")
+        tagged_items = self._get_tagged_items_by_tags(tags)
+        objects_id_list = [item.object_id for item in set(tagged_items)]
+        items = self.model._default_manager.filter(pk__in=objects_id_list)
         
-        objects_id = [item.object_id for item in set(items)]
-        
-        if not items:
-            return self.model._default_manager.none()
-        
-        return self.model._default_manager.filter(pk__in=objects_id)
+        return items
         
 

File tagging2/methods.py

     TaggedItem.objects.get_or_create(tag=tag, content_type=ctype, object_id=self.pk)
     
     
+def tag_list(self):
+    """
+    Allows you to iterate over object tags in templates like so::
+    
+        {% for tag in object.tag_list %}
+            <a href='#'>{{ tag }}</a>
+        {% endfor %}
+    """
+    return self.tags.split(", ")
+
     
 def tags_update(self, tag_names):
     """

File tagging2/utils.py

                         words.append(word)
                     buffer = []
                 open_quote = False
+            elif c == u"'":
+                if buffer:
+                    to_be_split.append(u''.join(buffer))
+                    buffer = []
+                # Find the matching quote
+                open_quote = True
+                c = i.next()
+                while c != u"'":
+                    buffer.append(c)
+                    c = i.next()
+                if buffer:
+                    word = u''.join(buffer).strip()
+                    if word:
+                        words.append(word)
+                    buffer = []
+                open_quote = False
             else:
                 if not saw_loose_comma and c == u',':
                     saw_loose_comma = True