models.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. """
  2. 34. Generic relations
  3. Generic relations let an object have a foreign key to any object through a
  4. content-type/object-id field. A ``GenericForeignKey`` field can point to any
  5. object, be it animal, vegetable, or mineral.
  6. The canonical example is tags (although this example implementation is *far*
  7. from complete).
  8. """
  9. from __future__ import unicode_literals
  10. from django.contrib.contenttypes.fields import (
  11. GenericForeignKey, GenericRelation
  12. )
  13. from django.contrib.contenttypes.models import ContentType
  14. from django.db import models
  15. from django.utils.encoding import python_2_unicode_compatible
  16. @python_2_unicode_compatible
  17. class TaggedItem(models.Model):
  18. """A tag on an item."""
  19. tag = models.SlugField()
  20. content_type = models.ForeignKey(ContentType)
  21. object_id = models.PositiveIntegerField()
  22. content_object = GenericForeignKey()
  23. class Meta:
  24. ordering = ["tag", "content_type__name"]
  25. def __str__(self):
  26. return self.tag
  27. class ValuableTaggedItem(TaggedItem):
  28. value = models.PositiveIntegerField()
  29. class AbstractComparison(models.Model):
  30. comparative = models.CharField(max_length=50)
  31. content_type1 = models.ForeignKey(ContentType, related_name="comparative1_set")
  32. object_id1 = models.PositiveIntegerField()
  33. first_obj = GenericForeignKey(ct_field="content_type1", fk_field="object_id1")
  34. @python_2_unicode_compatible
  35. class Comparison(AbstractComparison):
  36. """
  37. A model that tests having multiple GenericForeignKeys. One is defined
  38. through an inherited abstract model and one defined directly on this class.
  39. """
  40. content_type2 = models.ForeignKey(ContentType, related_name="comparative2_set")
  41. object_id2 = models.PositiveIntegerField()
  42. other_obj = GenericForeignKey(ct_field="content_type2", fk_field="object_id2")
  43. def __str__(self):
  44. return "%s is %s than %s" % (self.first_obj, self.comparative, self.other_obj)
  45. @python_2_unicode_compatible
  46. class Animal(models.Model):
  47. common_name = models.CharField(max_length=150)
  48. latin_name = models.CharField(max_length=150)
  49. tags = GenericRelation(TaggedItem, related_query_name='animal')
  50. comparisons = GenericRelation(Comparison,
  51. object_id_field="object_id1",
  52. content_type_field="content_type1")
  53. def __str__(self):
  54. return self.common_name
  55. @python_2_unicode_compatible
  56. class Vegetable(models.Model):
  57. name = models.CharField(max_length=150)
  58. is_yucky = models.BooleanField(default=True)
  59. tags = GenericRelation(TaggedItem)
  60. def __str__(self):
  61. return self.name
  62. @python_2_unicode_compatible
  63. class Mineral(models.Model):
  64. name = models.CharField(max_length=150)
  65. hardness = models.PositiveSmallIntegerField()
  66. # note the lack of an explicit GenericRelation here...
  67. def __str__(self):
  68. return self.name
  69. class GeckoManager(models.Manager):
  70. def get_queryset(self):
  71. return super(GeckoManager, self).get_queryset().filter(has_tail=True)
  72. class Gecko(models.Model):
  73. has_tail = models.BooleanField(default=False)
  74. objects = GeckoManager()
  75. # To test fix for #11263
  76. class Rock(Mineral):
  77. tags = GenericRelation(TaggedItem)
  78. class ManualPK(models.Model):
  79. id = models.IntegerField(primary_key=True)
  80. tags = GenericRelation(TaggedItem, related_query_name='manualpk')
  81. class ForProxyModelModel(models.Model):
  82. content_type = models.ForeignKey(ContentType)
  83. object_id = models.PositiveIntegerField()
  84. obj = GenericForeignKey(for_concrete_model=False)
  85. title = models.CharField(max_length=255, null=True)
  86. class ForConcreteModelModel(models.Model):
  87. content_type = models.ForeignKey(ContentType)
  88. object_id = models.PositiveIntegerField()
  89. obj = GenericForeignKey()
  90. class ConcreteRelatedModel(models.Model):
  91. bases = GenericRelation(ForProxyModelModel, for_concrete_model=False)
  92. class ProxyRelatedModel(ConcreteRelatedModel):
  93. class Meta:
  94. proxy = True
  95. # To test fix for #7551
  96. class AllowsNullGFK(models.Model):
  97. content_type = models.ForeignKey(ContentType, null=True)
  98. object_id = models.PositiveIntegerField(null=True)
  99. content_object = GenericForeignKey()