Search code examples
pythondjangotagsgeneric-relations

Django indirect generic relation


I've been trying to implement a tagging system for my application, where only certain tags are allowed for each content type.

I've tried setting the content type on the Tag model, and using this value on the TagAttribution model, and have got... interesting results.

Code:

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User

class Tag(models.Model):
    value = models.CharField(max_length=32)
    created_by = models.ForeignKey(User)
    appliable_to = models.ForeignKey(ContentType)

    def __unicode__(self):
        return self.value

class TagAttribution(models.Model):
    tag = models.ForeignKey(Tag)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('tag__appliable_to', 'object_id')

    def __unicode__(self):
        return "%s for id %s of class %s" % (self.tag.value, self.object_id, self.content_object.model) 

Shell test:

ct = ContentType.objects.get(model='company')
tag = Tag()
tag.value = 'value'
tag.created_by = User.objects.get(id=1)
tag.appliable_to = ct
tag.save()
ta = TagAttribution()
ta.tag = tag
ta.object_id = Company.objects.get(id=1).id
ta.content_object = ta.tag.appliable_to
ta.save()
ta

Output:

<TagAttribution: value for id 13 of class company>

I don't understand this behavior; why has it got the id 13 if I had used company id 1?


Solution

  • Error is here:

    ta.content_object = ta.tag.appliable_to
    

    The ta.content_object here is not Company object but ContentType. Correct code should be:

    ta.content_object = Company.objects.get(id=1).id
    

    Also, you don't have to set ta.object_id directly, it's done by GenericForeignKey field