import uuid from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType from django.db import models from django.db.models.query import ModelIterable from django.utils.functional import cached_property class Author(models.Model): name = models.CharField(max_length=50, unique=True) first_book = models.ForeignKey( "Book", models.CASCADE, related_name="first_time_authors" ) favorite_authors = models.ManyToManyField( "self", through="FavoriteAuthors", symmetrical=False, related_name="favors_me" ) class Meta: ordering = ["id"] def __str__(self): return self.name class AuthorWithAge(Author): author = models.OneToOneField(Author, models.CASCADE, parent_link=True) age = models.IntegerField() class FavoriteAuthors(models.Model): author = models.ForeignKey( Author, models.CASCADE, to_field="name", related_name="i_like" ) likes_author = models.ForeignKey( Author, models.CASCADE, to_field="name", related_name="likes_me" ) class Meta: ordering = ["id"] class AuthorAddress(models.Model): author = models.ForeignKey( Author, models.CASCADE, to_field="name", related_name="addresses" ) address = models.TextField() class Meta: ordering = ["id"] class Book(models.Model): title = models.CharField(max_length=255) authors = models.ManyToManyField(Author, related_name="books") class Meta: ordering = ["id"] class BookWithYear(Book): book = models.OneToOneField(Book, models.CASCADE, parent_link=True) published_year = models.IntegerField() aged_authors = models.ManyToManyField(AuthorWithAge, related_name="books_with_year") class Bio(models.Model): author = models.OneToOneField( Author, models.CASCADE, primary_key=True, to_field="name", ) books = models.ManyToManyField(Book, blank=True) class Reader(models.Model): name = models.CharField(max_length=50) books_read = models.ManyToManyField(Book, related_name="read_by") class Meta: ordering = ["id"] def __str__(self): return self.name class BookReview(models.Model): # Intentionally does not have a related name. book = models.ForeignKey(BookWithYear, models.CASCADE, null=True) notes = models.TextField(null=True, blank=True) # Models for default manager tests class Qualification(models.Model): name = models.CharField(max_length=10) class Meta: ordering = ["id"] class ModelIterableSubclass(ModelIterable): pass class TeacherQuerySet(models.QuerySet): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._iterable_class = ModelIterableSubclass class TeacherManager(models.Manager): def get_queryset(self): return super().get_queryset().prefetch_related("qualifications") class Teacher(models.Model): name = models.CharField(max_length=50) qualifications = models.ManyToManyField(Qualification) objects = TeacherManager() objects_custom = TeacherQuerySet.as_manager() class Meta: ordering = ["id"] def __str__(self): return "%s (%s)" % ( self.name, ", ".join(q.name for q in self.qualifications.all()), ) class Department(models.Model): name = models.CharField(max_length=50) teachers = models.ManyToManyField(Teacher) class Meta: ordering = ["id"] # GenericRelation/GenericForeignKey tests class TaggedItem(models.Model): tag = models.SlugField() content_type = models.ForeignKey( ContentType, models.CASCADE, related_name="taggeditem_set2", ) object_id = models.PositiveIntegerField() content_object = GenericForeignKey("content_type", "object_id") created_by_ct = models.ForeignKey( ContentType, models.SET_NULL, null=True, related_name="taggeditem_set3", ) created_by_fkey = models.PositiveIntegerField(null=True) created_by = GenericForeignKey( "created_by_ct", "created_by_fkey", ) favorite_ct = models.ForeignKey( ContentType, models.SET_NULL, null=True, related_name="taggeditem_set4", ) favorite_fkey = models.CharField(max_length=64, null=True) favorite = GenericForeignKey("favorite_ct", "favorite_fkey") class Meta: ordering = ["id"] class Article(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=20) class Bookmark(models.Model): url = models.URLField() tags = GenericRelation(TaggedItem, related_query_name="bookmarks") favorite_tags = GenericRelation( TaggedItem, content_type_field="favorite_ct", object_id_field="favorite_fkey", related_query_name="favorite_bookmarks", ) class Meta: ordering = ["id"] class Comment(models.Model): comment = models.TextField() # Content-object field content_type = models.ForeignKey(ContentType, models.CASCADE, null=True) object_pk = models.TextField() content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk") content_type_uuid = models.ForeignKey( ContentType, models.CASCADE, related_name="comments", null=True ) object_pk_uuid = models.TextField() content_object_uuid = GenericForeignKey( ct_field="content_type_uuid", fk_field="object_pk_uuid" ) class Meta: ordering = ["id"] # Models for lookup ordering tests class House(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=255) owner = models.ForeignKey("Person", models.SET_NULL, null=True) main_room = models.OneToOneField( "Room", models.SET_NULL, related_name="main_room_of", null=True ) class Meta: ordering = ["id"] class Room(models.Model): name = models.CharField(max_length=50) house = models.ForeignKey(House, models.CASCADE, related_name="rooms") class Meta: ordering = ["id"] class Person(models.Model): name = models.CharField(max_length=50) houses = models.ManyToManyField(House, related_name="occupants") @property def primary_house(self): # Assume business logic forces every person to have at least one house. return sorted(self.houses.all(), key=lambda house: -house.rooms.count())[0] @property def all_houses(self): return list(self.houses.all()) @cached_property def cached_all_houses(self): return self.all_houses class Meta: ordering = ["id"] # Models for nullable FK tests class Employee(models.Model): name = models.CharField(max_length=50) boss = models.ForeignKey("self", models.SET_NULL, null=True, related_name="serfs") class Meta: ordering = ["id"] # Ticket #19607 class LessonEntry(models.Model): name1 = models.CharField(max_length=200) name2 = models.CharField(max_length=200) class WordEntry(models.Model): lesson_entry = models.ForeignKey(LessonEntry, models.CASCADE) name = models.CharField(max_length=200) # Ticket #21410: Regression when related_name="+" class Author2(models.Model): name = models.CharField(max_length=50, unique=True) first_book = models.ForeignKey( "Book", models.CASCADE, related_name="first_time_authors+" ) favorite_books = models.ManyToManyField("Book", related_name="+") class Meta: ordering = ["id"] # Models for many-to-many with UUID pk test: class Pet(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=20) people = models.ManyToManyField(Person, related_name="pets") class Flea(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) current_room = models.ForeignKey( Room, models.SET_NULL, related_name="fleas", null=True ) pets_visited = models.ManyToManyField(Pet, related_name="fleas_hosted") people_visited = models.ManyToManyField(Person, related_name="fleas_hosted")