""" 34. Generic relations Generic relations let an object have a foreign key to any object through a content-type/object-id field. A ``GenericForeignKey`` field can point to any object, be it animal, vegetable, or mineral. The canonical example is tags (although this example implementation is *far* from complete). """ from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType from django.db import models class TaggedItem(models.Model): """A tag on an item.""" tag = models.SlugField() content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey() class Meta: ordering = ["tag", "content_type__name"] def __unicode__(self): return self.tag class ValuableTaggedItem(TaggedItem): value = models.PositiveIntegerField() class Comparison(models.Model): """ A model that tests having multiple GenericForeignKeys """ comparative = models.CharField(max_length=50) content_type1 = models.ForeignKey(ContentType, related_name="comparative1_set") object_id1 = models.PositiveIntegerField() content_type2 = models.ForeignKey(ContentType, related_name="comparative2_set") object_id2 = models.PositiveIntegerField() first_obj = generic.GenericForeignKey(ct_field="content_type1", fk_field="object_id1") other_obj = generic.GenericForeignKey(ct_field="content_type2", fk_field="object_id2") def __unicode__(self): return u"%s is %s than %s" % (self.first_obj, self.comparative, self.other_obj) class Animal(models.Model): common_name = models.CharField(max_length=150) latin_name = models.CharField(max_length=150) tags = generic.GenericRelation(TaggedItem) comparisons = generic.GenericRelation(Comparison, object_id_field="object_id1", content_type_field="content_type1") def __unicode__(self): return self.common_name class Vegetable(models.Model): name = models.CharField(max_length=150) is_yucky = models.BooleanField(default=True) tags = generic.GenericRelation(TaggedItem) def __unicode__(self): return self.name class Mineral(models.Model): name = models.CharField(max_length=150) hardness = models.PositiveSmallIntegerField() # note the lack of an explicit GenericRelation here... def __unicode__(self): return self.name