开发者

how to show tags related to a particular tag in django taggit ?

I want to show a list of tags that is related to a particular tag(in an optimised way). I wonder why django-taggit does not provide an inbuilt functional开发者_如何学运维ity for this common task.


The solution I have to offer does a bit more than what you're asking for because it allows to find related tags for a set of given tags, not for only a single given tag. In reality, this is probably what you want to do though. I'm not sure if it's really optimal in term of performance since it uses a subquery, but it works and I find it easy to understand.

First, here is the test case:

from django.test import TestCase
from .models import Item, get_related_tags


class RelatedTagsTest(TestCase):

    def setUp(self):
        article1 = Item.objects.create(title='Python vs. COBOL')
        article1.tags.add('programming', 'python', 'cobol')
        article2 = Item.objects.create(title='Python vs. Boa Constrictor')
        article2.tags.add('zoology', 'python', 'boa')
        article3 = Item.objects.create(title='COBOL vs. FORTRAN')
        article3.tags.add('cobol', 'fortran', 'programming')

    def test_unique_tag(self):
        self.assertEquals(get_related_tags('programming'),
                          ['cobol', 'fortran', 'python'])
        self.assertEquals(get_related_tags('python'),
                          ['boa', 'cobol', 'programming', 'zoology'])

    def test_multiple_tags(self):
        self.assertEquals(get_related_tags('boa', 'fortran'),
                          ['cobol', 'programming', 'python', 'zoology'])

As you can see, by "related tags" we mean the set of tags which are associated with items which are tagged with a set of given tags.

And here is our model with a function to get related tags:

from django.db import models
from taggit.managers import TaggableManager
from taggit.models import Tag

class Item(models.Model):
    title = models.CharField(max_length=100)
    tags = TaggableManager()


def get_related_tags(*tags):
    # Get a QuerySet of related items
    related_items = Item.objects.filter(tags__name__in=tags)

    # Get tags for those related items (I found the name of the lookup field by
    # reading taggit's source code)
    qs = Tag.objects.filter(taggit_taggeditem_items__item__in=related_items)

    # Exclude the tags we already have
    qs = qs.exclude(name__in=tags)

    # Order by name and remove duplicates
    qs = qs.order_by('name').distinct()

    # Return tag names to simplify test code, real code would probably return
    # Tag objects
    return [t.name for t in qs]

Note that you can easily add the number of items per tag using qs.annotate(count=Count('name')). It will be available as a count attribute on each Tag object.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜