models.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import uuid
  2. from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
  3. from django.contrib.contenttypes.models import ContentType
  4. from django.db import models
  5. from django.db.models.query import ModelIterable
  6. from django.utils.functional import cached_property
  7. class Author(models.Model):
  8. name = models.CharField(max_length=50, unique=True)
  9. first_book = models.ForeignKey(
  10. "Book", models.CASCADE, related_name="first_time_authors"
  11. )
  12. favorite_authors = models.ManyToManyField(
  13. "self", through="FavoriteAuthors", symmetrical=False, related_name="favors_me"
  14. )
  15. class Meta:
  16. ordering = ["id"]
  17. def __str__(self):
  18. return self.name
  19. class AuthorWithAge(Author):
  20. author = models.OneToOneField(Author, models.CASCADE, parent_link=True)
  21. age = models.IntegerField()
  22. class FavoriteAuthors(models.Model):
  23. author = models.ForeignKey(
  24. Author, models.CASCADE, to_field="name", related_name="i_like"
  25. )
  26. likes_author = models.ForeignKey(
  27. Author, models.CASCADE, to_field="name", related_name="likes_me"
  28. )
  29. is_active = models.BooleanField(default=True)
  30. class Meta:
  31. ordering = ["id"]
  32. class AuthorAddress(models.Model):
  33. author = models.ForeignKey(
  34. Author, models.CASCADE, to_field="name", related_name="addresses"
  35. )
  36. address = models.TextField()
  37. class Meta:
  38. ordering = ["id"]
  39. class Book(models.Model):
  40. title = models.CharField(max_length=255)
  41. authors = models.ManyToManyField(Author, related_name="books")
  42. class Meta:
  43. ordering = ["id"]
  44. class BookWithYear(Book):
  45. book = models.OneToOneField(Book, models.CASCADE, parent_link=True)
  46. published_year = models.IntegerField()
  47. aged_authors = models.ManyToManyField(AuthorWithAge, related_name="books_with_year")
  48. class Bio(models.Model):
  49. author = models.OneToOneField(
  50. Author,
  51. models.CASCADE,
  52. primary_key=True,
  53. to_field="name",
  54. )
  55. books = models.ManyToManyField(Book, blank=True)
  56. class Reader(models.Model):
  57. name = models.CharField(max_length=50)
  58. books_read = models.ManyToManyField(Book, related_name="read_by")
  59. class Meta:
  60. ordering = ["id"]
  61. def __str__(self):
  62. return self.name
  63. class BookReview(models.Model):
  64. # Intentionally does not have a related name.
  65. book = models.ForeignKey(BookWithYear, models.CASCADE, null=True)
  66. notes = models.TextField(null=True, blank=True)
  67. # Models for default manager tests
  68. class Qualification(models.Model):
  69. name = models.CharField(max_length=10)
  70. class Meta:
  71. ordering = ["id"]
  72. class ModelIterableSubclass(ModelIterable):
  73. pass
  74. class TeacherQuerySet(models.QuerySet):
  75. def __init__(self, *args, **kwargs):
  76. super().__init__(*args, **kwargs)
  77. self._iterable_class = ModelIterableSubclass
  78. class TeacherManager(models.Manager):
  79. def get_queryset(self):
  80. return super().get_queryset().prefetch_related("qualifications")
  81. class Teacher(models.Model):
  82. name = models.CharField(max_length=50)
  83. qualifications = models.ManyToManyField(Qualification)
  84. objects = TeacherManager()
  85. objects_custom = TeacherQuerySet.as_manager()
  86. class Meta:
  87. ordering = ["id"]
  88. def __str__(self):
  89. return "%s (%s)" % (
  90. self.name,
  91. ", ".join(q.name for q in self.qualifications.all()),
  92. )
  93. class Department(models.Model):
  94. name = models.CharField(max_length=50)
  95. teachers = models.ManyToManyField(Teacher)
  96. class Meta:
  97. ordering = ["id"]
  98. # GenericRelation/GenericForeignKey tests
  99. class TaggedItem(models.Model):
  100. tag = models.SlugField()
  101. content_type = models.ForeignKey(
  102. ContentType,
  103. models.CASCADE,
  104. related_name="taggeditem_set2",
  105. )
  106. object_id = models.PositiveIntegerField()
  107. content_object = GenericForeignKey("content_type", "object_id")
  108. created_by_ct = models.ForeignKey(
  109. ContentType,
  110. models.SET_NULL,
  111. null=True,
  112. related_name="taggeditem_set3",
  113. )
  114. created_by_fkey = models.PositiveIntegerField(null=True)
  115. created_by = GenericForeignKey(
  116. "created_by_ct",
  117. "created_by_fkey",
  118. )
  119. favorite_ct = models.ForeignKey(
  120. ContentType,
  121. models.SET_NULL,
  122. null=True,
  123. related_name="taggeditem_set4",
  124. )
  125. favorite_fkey = models.CharField(max_length=64, null=True)
  126. favorite = GenericForeignKey("favorite_ct", "favorite_fkey")
  127. class Meta:
  128. ordering = ["id"]
  129. class Article(models.Model):
  130. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  131. name = models.CharField(max_length=20)
  132. class Bookmark(models.Model):
  133. url = models.URLField()
  134. tags = GenericRelation(TaggedItem, related_query_name="bookmarks")
  135. favorite_tags = GenericRelation(
  136. TaggedItem,
  137. content_type_field="favorite_ct",
  138. object_id_field="favorite_fkey",
  139. related_query_name="favorite_bookmarks",
  140. )
  141. class Meta:
  142. ordering = ["id"]
  143. class Comment(models.Model):
  144. comment = models.TextField()
  145. # Content-object field
  146. content_type = models.ForeignKey(ContentType, models.CASCADE, null=True)
  147. object_pk = models.TextField()
  148. content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk")
  149. content_type_uuid = models.ForeignKey(
  150. ContentType, models.CASCADE, related_name="comments", null=True
  151. )
  152. object_pk_uuid = models.TextField()
  153. content_object_uuid = GenericForeignKey(
  154. ct_field="content_type_uuid", fk_field="object_pk_uuid"
  155. )
  156. class Meta:
  157. ordering = ["id"]
  158. # Models for lookup ordering tests
  159. class House(models.Model):
  160. name = models.CharField(max_length=50)
  161. address = models.CharField(max_length=255)
  162. owner = models.ForeignKey("Person", models.SET_NULL, null=True)
  163. main_room = models.OneToOneField(
  164. "Room", models.SET_NULL, related_name="main_room_of", null=True
  165. )
  166. class Meta:
  167. ordering = ["id"]
  168. class Room(models.Model):
  169. name = models.CharField(max_length=50)
  170. house = models.ForeignKey(House, models.CASCADE, related_name="rooms")
  171. class Meta:
  172. ordering = ["id"]
  173. class Person(models.Model):
  174. name = models.CharField(max_length=50)
  175. houses = models.ManyToManyField(House, related_name="occupants")
  176. @property
  177. def primary_house(self):
  178. # Assume business logic forces every person to have at least one house.
  179. return sorted(self.houses.all(), key=lambda house: -house.rooms.count())[0]
  180. @property
  181. def all_houses(self):
  182. return list(self.houses.all())
  183. @cached_property
  184. def cached_all_houses(self):
  185. return self.all_houses
  186. class Meta:
  187. ordering = ["id"]
  188. # Models for nullable FK tests
  189. class Employee(models.Model):
  190. name = models.CharField(max_length=50)
  191. boss = models.ForeignKey("self", models.SET_NULL, null=True, related_name="serfs")
  192. class Meta:
  193. ordering = ["id"]
  194. # Ticket #19607
  195. class LessonEntry(models.Model):
  196. name1 = models.CharField(max_length=200)
  197. name2 = models.CharField(max_length=200)
  198. class WordEntry(models.Model):
  199. lesson_entry = models.ForeignKey(LessonEntry, models.CASCADE)
  200. name = models.CharField(max_length=200)
  201. # Ticket #21410: Regression when related_name="+"
  202. class Author2(models.Model):
  203. name = models.CharField(max_length=50, unique=True)
  204. first_book = models.ForeignKey(
  205. "Book", models.CASCADE, related_name="first_time_authors+"
  206. )
  207. favorite_books = models.ManyToManyField("Book", related_name="+")
  208. class Meta:
  209. ordering = ["id"]
  210. # Models for many-to-many with UUID pk test:
  211. class Pet(models.Model):
  212. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  213. name = models.CharField(max_length=20)
  214. people = models.ManyToManyField(Person, related_name="pets")
  215. class Flea(models.Model):
  216. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  217. current_room = models.ForeignKey(
  218. Room, models.SET_NULL, related_name="fleas", null=True
  219. )
  220. pets_visited = models.ManyToManyField(Pet, related_name="fleas_hosted")
  221. people_visited = models.ManyToManyField(Person, related_name="fleas_hosted")