models.py 8.0 KB

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