123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- """
- 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 __future__ import unicode_literals
- from django.contrib.contenttypes.fields import (
- GenericForeignKey, GenericRelation
- )
- from django.contrib.contenttypes.models import ContentType
- from django.db import models
- from django.utils.encoding import python_2_unicode_compatible
- @python_2_unicode_compatible
- class TaggedItem(models.Model):
- """A tag on an item."""
- tag = models.SlugField()
- content_type = models.ForeignKey(ContentType)
- object_id = models.PositiveIntegerField()
- content_object = GenericForeignKey()
- class Meta:
- ordering = ["tag", "content_type__name"]
- def __str__(self):
- return self.tag
- class ValuableTaggedItem(TaggedItem):
- value = models.PositiveIntegerField()
- class AbstractComparison(models.Model):
- comparative = models.CharField(max_length=50)
- content_type1 = models.ForeignKey(ContentType, related_name="comparative1_set")
- object_id1 = models.PositiveIntegerField()
- first_obj = GenericForeignKey(ct_field="content_type1", fk_field="object_id1")
- @python_2_unicode_compatible
- class Comparison(AbstractComparison):
- """
- A model that tests having multiple GenericForeignKeys. One is defined
- through an inherited abstract model and one defined directly on this class.
- """
- content_type2 = models.ForeignKey(ContentType, related_name="comparative2_set")
- object_id2 = models.PositiveIntegerField()
- other_obj = GenericForeignKey(ct_field="content_type2", fk_field="object_id2")
- def __str__(self):
- return "%s is %s than %s" % (self.first_obj, self.comparative, self.other_obj)
- @python_2_unicode_compatible
- class Animal(models.Model):
- common_name = models.CharField(max_length=150)
- latin_name = models.CharField(max_length=150)
- tags = GenericRelation(TaggedItem, related_query_name='animal')
- comparisons = GenericRelation(Comparison,
- object_id_field="object_id1",
- content_type_field="content_type1")
- def __str__(self):
- return self.common_name
- @python_2_unicode_compatible
- class Vegetable(models.Model):
- name = models.CharField(max_length=150)
- is_yucky = models.BooleanField(default=True)
- tags = GenericRelation(TaggedItem)
- def __str__(self):
- return self.name
- @python_2_unicode_compatible
- class Mineral(models.Model):
- name = models.CharField(max_length=150)
- hardness = models.PositiveSmallIntegerField()
- # note the lack of an explicit GenericRelation here...
- def __str__(self):
- return self.name
- class GeckoManager(models.Manager):
- def get_queryset(self):
- return super(GeckoManager, self).get_queryset().filter(has_tail=True)
- class Gecko(models.Model):
- has_tail = models.BooleanField(default=False)
- objects = GeckoManager()
- # To test fix for #11263
- class Rock(Mineral):
- tags = GenericRelation(TaggedItem)
- class ManualPK(models.Model):
- id = models.IntegerField(primary_key=True)
- tags = GenericRelation(TaggedItem, related_query_name='manualpk')
- class ForProxyModelModel(models.Model):
- content_type = models.ForeignKey(ContentType)
- object_id = models.PositiveIntegerField()
- obj = GenericForeignKey(for_concrete_model=False)
- title = models.CharField(max_length=255, null=True)
- class ForConcreteModelModel(models.Model):
- content_type = models.ForeignKey(ContentType)
- object_id = models.PositiveIntegerField()
- obj = GenericForeignKey()
- class ConcreteRelatedModel(models.Model):
- bases = GenericRelation(ForProxyModelModel, for_concrete_model=False)
- class ProxyRelatedModel(ConcreteRelatedModel):
- class Meta:
- proxy = True
- # To test fix for #7551
- class AllowsNullGFK(models.Model):
- content_type = models.ForeignKey(ContentType, null=True)
- object_id = models.PositiveIntegerField(null=True)
- content_object = GenericForeignKey()
|