Commits

Max Peterson committed 7bdd161

Added as new

Comments (0)

Files changed (9)

+recursive-include taggitextras/templates *.html
+from distutils.core import setup
+setup(
+    name = "taggitextras",
+    packages = ["taggitextras", ],
+    include_package_data=True,
+    install_requires=[
+        "django-taggit",
+    ],
+    version = "0.1",
+    description = "Templatetags for django-taggit.",
+    author = "Incuna Ltd",
+    author_email = "admin@incuna.com",
+    url = "http://incuna.com/",
+)

taggitextras/__init__.py

+from django.conf import settings
+
+# define the minimal weight of a tag in the tagcloud
+TAGCLOUD_MIN = getattr(settings, 'TAGGIT_TAGCLOUD_MIN', 1.0)
+
+# define the maximum weight of a tag in the tagcloud 
+TAGCLOUD_MAX = getattr(settings, 'TAGGIT_TAGCLOUD_MAX', 6.0) 
+

taggitextras/models.py

Empty file added.

taggitextras/templates/taggitextras/tagcloud.html

+<div>
+{% for tag in tags %}
+<font size={{tag.weight|floatformat:0}}>{{tag}}</font> 
+{% endfor %}
+</div>

taggitextras/templates/taggitextras/taglist.html

+<ul>
+{% for tag in tags %}
+<li>{{tag}}</li>
+{% endfor %}
+</ul>

taggitextras/templatetags/__init__.py

Empty file added.

taggitextras/templatetags/taggitextras_tags.py

+from django import template
+from django.db import models
+from django.db.models import Count
+from django.core.exceptions import FieldError
+from django.contrib.contenttypes.models import ContentType
+
+from incuna.template.defaulttags import parse_tokens
+
+
+from taggit.models import TaggedItem, Tag
+
+from taggitextras import TAGCLOUD_MAX, TAGCLOUD_MIN
+
+register = template.Library()
+
+def get_queryset(forvar=None):
+    if forvar is None:
+        # get all tags
+        queryset = Tag.objects.all()
+    elif isinstance(forvar, basestring):
+        # extract app label and model name
+        beginning, applabel, model = None, None, None
+        try:
+            beginning, applabel, model = forvar.rsplit('.', 2)
+        except ValueError:
+            try:
+                applabel, model = forvar.rsplit('.', 1)
+            except ValueError:
+                applabel = forvar
+        
+        # filter tagged items        
+        if applabel:
+            queryset = TaggedItem.objects.filter(content_type__app_label=applabel.lower())
+        if model:
+            queryset = queryset.filter(content_type__model=model.lower())
+            
+        # get tags
+        tag_ids = queryset.values_list('tag_id', flat=True)
+        queryset = Tag.objects.filter(id__in=tag_ids)
+    elif isinstance(forvar, models.query.QuerySet):
+        if forvar.model == Tag:
+            queryset = forvar
+        else:
+            taggeditems = TaggedItem.objects.filter(content_type=ContentType.objects.get_for_model(forvar.model), object_id__in=forvar)
+            queryset = Tag.objects.filter(id__in=taggeditems)
+    elif isinstance(forvar, models.Model):
+            taggeditems = TaggedItem.objects.filter(content_type=ContentType.objects.get_for_model(forvar), object_id=forvar.pk)
+            queryset = Tag.objects.filter(id__in=taggeditems)
+    else:
+        # What is forvar??
+        queryset = forvar
+
+    # Retain compatibility with older versions of Django taggit
+    # a version check (for example taggit.VERSION <= (0,8,0)) does NOT
+    # work because of the version (0,8,0) of the current dev version of django-taggit
+    try:
+        return queryset.annotate(num_times=Count('taggit_taggeditem_items'))
+    except FieldError:
+        return queryset.annotate(num_times=Count('taggeditem_items'))
+
+def get_weight_fun(t_min, t_max, f_min, f_max):
+    def weight_fun(f_i, t_min=t_min, t_max=t_max, f_min=f_min, f_max=f_max):
+        # Prevent a division by zero here, found to occur under some
+        # pathological but nevertheless actually occurring circumstances.
+        if f_max == f_min:
+            mult_fac = 1.0
+        else:
+            mult_fac = float(t_max-t_min)/float(f_max-f_min)
+            
+        return t_max - (f_max-f_i)*mult_fac
+    return weight_fun
+
+class TaglistNode(template.Node):
+    """
+        Get a list of tags.
+        If as varname is specified then add the result to the context.
+
+        Usage:
+            {% taglist %}
+            OR
+            {% taglist 'auth.User' %}
+            OR
+            {% taglist 'auth' %}
+            OR
+            {% taglist users %}
+            OR
+            {% taglist user %}
+            OR
+            {% taglist as tags %}
+            OR
+            {% taglist 'auth.User' as tags %}
+            ...
+    """
+    def __init__(self, forvar=None, varname=None):
+        self.forvar = forvar
+        self.varname = varname
+
+    def render(self, context):
+        forvar = self.forvar and self.forvar.resolve(context)
+
+        queryset = get_queryset(forvar).order_by('-num_times')
+
+        if self.varname is not None:
+            context[self.varname] = queryset
+            return ''
+        else:
+            t = template.loader.select_template(['taggitextras/taglist.html'])
+            context.push()
+            context['tags'] = queryset
+            output = t.render(context)
+            context.pop()
+
+            return output
+
+@register.tag()
+def taglist(parser, token):
+    bits = token.split_contents() 
+
+    varname = None
+    try:
+        if bits[-2] == 'as':
+            varname = bits[-1]
+            bits = bits[:-2]
+    except IndexError:
+        pass
+
+    args, kwargs = parse_tokens(parser, bits)
+    if varname is not None:
+        kwargs['varname'] = varname
+
+    return TaglistNode(*args, **kwargs)
+
+
+class TaglistCloudNode(template.Node):
+    """
+        Get a list of tags.
+        If as varname is specified then add the result to the context.
+
+        Usage:
+            {% taglist %}
+            OR
+            {% taglist 'auth.User' %}
+            OR
+            {% taglist 'auth' %}
+            OR
+            {% taglist users %}
+            OR
+            {% taglist user %}
+            OR
+            {% taglist as tags %}
+            OR
+            {% taglist 'auth.User' as tags %}
+            ...
+    """
+    def __init__(self, forvar=None, varname=None):
+        self.forvar = forvar
+        self.varname = varname
+
+    def render(self, context):
+        forvar = self.forvar and self.forvar.resolve(context)
+
+        queryset = get_queryset(forvar)
+        num_times = queryset.values_list('num_times', flat=True)
+        if(len(num_times) != 0):
+            weight_fun = get_weight_fun(TAGCLOUD_MIN, TAGCLOUD_MAX, min(num_times), max(num_times))
+            queryset = queryset.order_by('name')
+            for tag in queryset:
+                tag.weight = weight_fun(tag.num_times)
+
+        if self.varname is not None:
+            context[self.varname] = queryset
+            return ''
+        else:
+            t = template.loader.select_template(['taggitextras/tagcloud.html'])
+            context.push()
+            context['tags'] = queryset
+            output = t.render(context)
+            context.pop()
+
+        return output
+
+@register.tag()
+def tagcloud(parser, token):
+    bits = token.split_contents() 
+
+    varname = None
+    try:
+        if bits[-2] == 'as':
+            varname = bits[-1]
+            bits = bits[:-2]
+    except IndexError:
+        pass
+
+    args, kwargs = parse_tokens(parser, bits)
+    if varname is not None:
+        kwargs['varname'] = varname
+
+    return TaglistCloudNode(*args, **kwargs)
+

taggitextras/tests.py

+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+