diff options
author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/prefetch_related | |
parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
download | django-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/prefetch_related')
-rw-r--r-- | tests/prefetch_related/models.py | 139 | ||||
-rw-r--r-- | tests/prefetch_related/test_prefetch_related_objects.py | 76 | ||||
-rw-r--r-- | tests/prefetch_related/test_uuid.py | 76 | ||||
-rw-r--r-- | tests/prefetch_related/tests.py | 1305 |
4 files changed, 947 insertions, 649 deletions
diff --git a/tests/prefetch_related/models.py b/tests/prefetch_related/models.py index 0ded7e8b4a..0d9dbe6066 100644 --- a/tests/prefetch_related/models.py +++ b/tests/prefetch_related/models.py @@ -1,8 +1,6 @@ import uuid -from django.contrib.contenttypes.fields import ( - GenericForeignKey, GenericRelation, -) +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 @@ -11,12 +9,15 @@ 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') + 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') + "self", through="FavoriteAuthors", symmetrical=False, related_name="favors_me" + ) class Meta: - ordering = ['id'] + ordering = ["id"] def __str__(self): return self.name @@ -28,34 +29,39 @@ class AuthorWithAge(Author): 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') + 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'] + ordering = ["id"] class AuthorAddress(models.Model): - author = models.ForeignKey(Author, models.CASCADE, to_field='name', related_name='addresses') + author = models.ForeignKey( + Author, models.CASCADE, to_field="name", related_name="addresses" + ) address = models.TextField() class Meta: - ordering = ['id'] + ordering = ["id"] class Book(models.Model): title = models.CharField(max_length=255) - authors = models.ManyToManyField(Author, related_name='books') + authors = models.ManyToManyField(Author, related_name="books") class Meta: - ordering = ['id'] + 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') + aged_authors = models.ManyToManyField(AuthorWithAge, related_name="books_with_year") class Bio(models.Model): @@ -63,17 +69,17 @@ class Bio(models.Model): Author, models.CASCADE, primary_key=True, - to_field='name', + 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') + books_read = models.ManyToManyField(Book, related_name="read_by") class Meta: - ordering = ['id'] + ordering = ["id"] def __str__(self): return self.name @@ -87,11 +93,12 @@ class BookReview(models.Model): # Models for default manager tests + class Qualification(models.Model): name = models.CharField(max_length=10) class Meta: - ordering = ['id'] + ordering = ["id"] class ModelIterableSubclass(ModelIterable): @@ -106,7 +113,7 @@ class TeacherQuerySet(models.QuerySet): class TeacherManager(models.Manager): def get_queryset(self): - return super().get_queryset().prefetch_related('qualifications') + return super().get_queryset().prefetch_related("qualifications") class Teacher(models.Model): @@ -117,10 +124,13 @@ class Teacher(models.Model): objects_custom = TeacherQuerySet.as_manager() class Meta: - ordering = ['id'] + ordering = ["id"] def __str__(self): - return "%s (%s)" % (self.name, ", ".join(q.name for q in self.qualifications.all())) + return "%s (%s)" % ( + self.name, + ", ".join(q.name for q in self.qualifications.all()), + ) class Department(models.Model): @@ -128,11 +138,12 @@ class Department(models.Model): teachers = models.ManyToManyField(Teacher) class Meta: - ordering = ['id'] + ordering = ["id"] # GenericRelation/GenericForeignKey tests + class TaggedItem(models.Model): tag = models.SlugField() content_type = models.ForeignKey( @@ -141,26 +152,29 @@ class TaggedItem(models.Model): related_name="taggeditem_set2", ) object_id = models.PositiveIntegerField() - content_object = GenericForeignKey('content_type', 'object_id') + content_object = GenericForeignKey("content_type", "object_id") created_by_ct = models.ForeignKey( ContentType, models.SET_NULL, null=True, - related_name='taggeditem_set3', + related_name="taggeditem_set3", ) created_by_fkey = models.PositiveIntegerField(null=True) - created_by = GenericForeignKey('created_by_ct', 'created_by_fkey',) + created_by = GenericForeignKey( + "created_by_ct", + "created_by_fkey", + ) favorite_ct = models.ForeignKey( ContentType, models.SET_NULL, null=True, - related_name='taggeditem_set4', + related_name="taggeditem_set4", ) favorite_fkey = models.CharField(max_length=64, null=True) - favorite = GenericForeignKey('favorite_ct', 'favorite_fkey') + favorite = GenericForeignKey("favorite_ct", "favorite_fkey") class Meta: - ordering = ['id'] + ordering = ["id"] class Article(models.Model): @@ -170,14 +184,16 @@ class Article(models.Model): 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') + 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'] + ordering = ["id"] class Comment(models.Model): @@ -187,37 +203,44 @@ class Comment(models.Model): 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) + 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') + content_object_uuid = GenericForeignKey( + ct_field="content_type_uuid", fk_field="object_pk_uuid" + ) class Meta: - ordering = ['id'] + 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) + 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'] + ordering = ["id"] class Room(models.Model): name = models.CharField(max_length=50) - house = models.ForeignKey(House, models.CASCADE, related_name='rooms') + house = models.ForeignKey(House, models.CASCADE, related_name="rooms") class Meta: - ordering = ['id'] + ordering = ["id"] class Person(models.Model): name = models.CharField(max_length=50) - houses = models.ManyToManyField(House, related_name='occupants') + houses = models.ManyToManyField(House, related_name="occupants") @property def primary_house(self): @@ -233,21 +256,23 @@ class Person(models.Model): return self.all_houses class Meta: - ordering = ['id'] + 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') + boss = models.ForeignKey("self", models.SET_NULL, null=True, related_name="serfs") class Meta: - ordering = ['id'] + ordering = ["id"] # Ticket #19607 + class LessonEntry(models.Model): name1 = models.CharField(max_length=200) name2 = models.CharField(max_length=200) @@ -260,25 +285,31 @@ class WordEntry(models.Model): # 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='+') + first_book = models.ForeignKey( + "Book", models.CASCADE, related_name="first_time_authors+" + ) + favorite_books = models.ManyToManyField("Book", related_name="+") class Meta: - ordering = ['id'] + 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') + 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') + 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") diff --git a/tests/prefetch_related/test_prefetch_related_objects.py b/tests/prefetch_related/test_prefetch_related_objects.py index 20d4da5a0a..ca1f904c52 100644 --- a/tests/prefetch_related/test_prefetch_related_objects.py +++ b/tests/prefetch_related/test_prefetch_related_objects.py @@ -9,25 +9,26 @@ class PrefetchRelatedObjectsTests(TestCase): Since prefetch_related_objects() is just the inner part of prefetch_related(), only do basic tests to ensure its API hasn't changed. """ + @classmethod def setUpTestData(cls): - cls.book1 = Book.objects.create(title='Poems') - cls.book2 = Book.objects.create(title='Jane Eyre') - cls.book3 = Book.objects.create(title='Wuthering Heights') - cls.book4 = Book.objects.create(title='Sense and Sensibility') + cls.book1 = Book.objects.create(title="Poems") + cls.book2 = Book.objects.create(title="Jane Eyre") + cls.book3 = Book.objects.create(title="Wuthering Heights") + cls.book4 = Book.objects.create(title="Sense and Sensibility") - cls.author1 = Author.objects.create(name='Charlotte', first_book=cls.book1) - cls.author2 = Author.objects.create(name='Anne', first_book=cls.book1) - cls.author3 = Author.objects.create(name='Emily', first_book=cls.book1) - cls.author4 = Author.objects.create(name='Jane', first_book=cls.book4) + cls.author1 = Author.objects.create(name="Charlotte", first_book=cls.book1) + cls.author2 = Author.objects.create(name="Anne", first_book=cls.book1) + cls.author3 = Author.objects.create(name="Emily", first_book=cls.book1) + cls.author4 = Author.objects.create(name="Jane", first_book=cls.book4) cls.book1.authors.add(cls.author1, cls.author2, cls.author3) cls.book2.authors.add(cls.author1) cls.book3.authors.add(cls.author3) cls.book4.authors.add(cls.author4) - cls.reader1 = Reader.objects.create(name='Amy') - cls.reader2 = Reader.objects.create(name='Belinda') + cls.reader1 = Reader.objects.create(name="Amy") + cls.reader2 = Reader.objects.create(name="Belinda") cls.reader1.books_read.add(cls.book1, cls.book4) cls.reader2.books_read.add(cls.book2, cls.book4) @@ -35,20 +36,22 @@ class PrefetchRelatedObjectsTests(TestCase): def test_unknown(self): book1 = Book.objects.get(id=self.book1.id) with self.assertRaises(AttributeError): - prefetch_related_objects([book1], 'unknown_attribute') + prefetch_related_objects([book1], "unknown_attribute") def test_m2m_forward(self): book1 = Book.objects.get(id=self.book1.id) with self.assertNumQueries(1): - prefetch_related_objects([book1], 'authors') + prefetch_related_objects([book1], "authors") with self.assertNumQueries(0): - self.assertCountEqual(book1.authors.all(), [self.author1, self.author2, self.author3]) + self.assertCountEqual( + book1.authors.all(), [self.author1, self.author2, self.author3] + ) def test_m2m_reverse(self): author1 = Author.objects.get(id=self.author1.id) with self.assertNumQueries(1): - prefetch_related_objects([author1], 'books') + prefetch_related_objects([author1], "books") with self.assertNumQueries(0): self.assertCountEqual(author1.books.all(), [self.book1, self.book2]) @@ -56,7 +59,7 @@ class PrefetchRelatedObjectsTests(TestCase): def test_foreignkey_forward(self): authors = list(Author.objects.all()) with self.assertNumQueries(1): - prefetch_related_objects(authors, 'first_book') + prefetch_related_objects(authors, "first_book") with self.assertNumQueries(0): [author.first_book for author in authors] @@ -64,7 +67,7 @@ class PrefetchRelatedObjectsTests(TestCase): def test_foreignkey_reverse(self): books = list(Book.objects.all()) with self.assertNumQueries(1): - prefetch_related_objects(books, 'first_time_authors') + prefetch_related_objects(books, "first_time_authors") with self.assertNumQueries(0): [list(book.first_time_authors.all()) for book in books] @@ -73,7 +76,7 @@ class PrefetchRelatedObjectsTests(TestCase): """A m2m can be followed through another m2m.""" authors = list(Author.objects.all()) with self.assertNumQueries(2): - prefetch_related_objects(authors, 'books__read_by') + prefetch_related_objects(authors, "books__read_by") with self.assertNumQueries(0): self.assertEqual( @@ -82,38 +85,44 @@ class PrefetchRelatedObjectsTests(TestCase): for a in authors ], [ - [['Amy'], ['Belinda']], # Charlotte - Poems, Jane Eyre - [['Amy']], # Anne - Poems - [['Amy'], []], # Emily - Poems, Wuthering Heights - [['Amy', 'Belinda']], # Jane - Sense and Sense - ] + [["Amy"], ["Belinda"]], # Charlotte - Poems, Jane Eyre + [["Amy"]], # Anne - Poems + [["Amy"], []], # Emily - Poems, Wuthering Heights + [["Amy", "Belinda"]], # Jane - Sense and Sense + ], ) def test_prefetch_object(self): book1 = Book.objects.get(id=self.book1.id) with self.assertNumQueries(1): - prefetch_related_objects([book1], Prefetch('authors')) + prefetch_related_objects([book1], Prefetch("authors")) with self.assertNumQueries(0): - self.assertCountEqual(book1.authors.all(), [self.author1, self.author2, self.author3]) + self.assertCountEqual( + book1.authors.all(), [self.author1, self.author2, self.author3] + ) def test_prefetch_object_twice(self): book1 = Book.objects.get(id=self.book1.id) book2 = Book.objects.get(id=self.book2.id) with self.assertNumQueries(1): - prefetch_related_objects([book1], Prefetch('authors')) + prefetch_related_objects([book1], Prefetch("authors")) with self.assertNumQueries(1): - prefetch_related_objects([book1, book2], Prefetch('authors')) + prefetch_related_objects([book1, book2], Prefetch("authors")) with self.assertNumQueries(0): self.assertCountEqual(book2.authors.all(), [self.author1]) def test_prefetch_object_to_attr(self): book1 = Book.objects.get(id=self.book1.id) with self.assertNumQueries(1): - prefetch_related_objects([book1], Prefetch('authors', to_attr='the_authors')) + prefetch_related_objects( + [book1], Prefetch("authors", to_attr="the_authors") + ) with self.assertNumQueries(0): - self.assertCountEqual(book1.the_authors, [self.author1, self.author2, self.author3]) + self.assertCountEqual( + book1.the_authors, [self.author1, self.author2, self.author3] + ) def test_prefetch_object_to_attr_twice(self): book1 = Book.objects.get(id=self.book1.id) @@ -121,12 +130,12 @@ class PrefetchRelatedObjectsTests(TestCase): with self.assertNumQueries(1): prefetch_related_objects( [book1], - Prefetch('authors', to_attr='the_authors'), + Prefetch("authors", to_attr="the_authors"), ) with self.assertNumQueries(1): prefetch_related_objects( [book1, book2], - Prefetch('authors', to_attr='the_authors'), + Prefetch("authors", to_attr="the_authors"), ) with self.assertNumQueries(0): self.assertCountEqual(book2.the_authors, [self.author1]) @@ -136,7 +145,12 @@ class PrefetchRelatedObjectsTests(TestCase): with self.assertNumQueries(1): prefetch_related_objects( [book1], - Prefetch('authors', queryset=Author.objects.filter(id__in=[self.author1.id, self.author2.id])) + Prefetch( + "authors", + queryset=Author.objects.filter( + id__in=[self.author1.id, self.author2.id] + ), + ), ) with self.assertNumQueries(0): diff --git a/tests/prefetch_related/test_uuid.py b/tests/prefetch_related/test_uuid.py index 11a2474f4a..55332b7b5d 100644 --- a/tests/prefetch_related/test_uuid.py +++ b/tests/prefetch_related/test_uuid.py @@ -4,66 +4,64 @@ from .models import Flea, House, Person, Pet, Room class UUIDPrefetchRelated(TestCase): - def test_prefetch_related_from_uuid_model(self): - Pet.objects.create(name='Fifi').people.add( - Person.objects.create(name='Ellen'), - Person.objects.create(name='George'), + Pet.objects.create(name="Fifi").people.add( + Person.objects.create(name="Ellen"), + Person.objects.create(name="George"), ) with self.assertNumQueries(2): - pet = Pet.objects.prefetch_related('people').get(name='Fifi') + pet = Pet.objects.prefetch_related("people").get(name="Fifi") with self.assertNumQueries(0): self.assertEqual(2, len(pet.people.all())) def test_prefetch_related_to_uuid_model(self): - Person.objects.create(name='Bella').pets.add( - Pet.objects.create(name='Socks'), - Pet.objects.create(name='Coffee'), + Person.objects.create(name="Bella").pets.add( + Pet.objects.create(name="Socks"), + Pet.objects.create(name="Coffee"), ) with self.assertNumQueries(2): - person = Person.objects.prefetch_related('pets').get(name='Bella') + person = Person.objects.prefetch_related("pets").get(name="Bella") with self.assertNumQueries(0): self.assertEqual(2, len(person.pets.all())) def test_prefetch_related_from_uuid_model_to_uuid_model(self): fleas = [Flea.objects.create() for i in range(3)] - Pet.objects.create(name='Fifi').fleas_hosted.add(*fleas) - Pet.objects.create(name='Bobo').fleas_hosted.add(*fleas) + Pet.objects.create(name="Fifi").fleas_hosted.add(*fleas) + Pet.objects.create(name="Bobo").fleas_hosted.add(*fleas) with self.assertNumQueries(2): - pet = Pet.objects.prefetch_related('fleas_hosted').get(name='Fifi') + pet = Pet.objects.prefetch_related("fleas_hosted").get(name="Fifi") with self.assertNumQueries(0): self.assertEqual(3, len(pet.fleas_hosted.all())) with self.assertNumQueries(2): - flea = Flea.objects.prefetch_related('pets_visited').get(pk=fleas[0].pk) + flea = Flea.objects.prefetch_related("pets_visited").get(pk=fleas[0].pk) with self.assertNumQueries(0): self.assertEqual(2, len(flea.pets_visited.all())) def test_prefetch_related_from_uuid_model_to_uuid_model_with_values_flat(self): - pet = Pet.objects.create(name='Fifi') + pet = Pet.objects.create(name="Fifi") pet.people.add( - Person.objects.create(name='Ellen'), - Person.objects.create(name='George'), + Person.objects.create(name="Ellen"), + Person.objects.create(name="George"), ) self.assertSequenceEqual( - Pet.objects.prefetch_related('fleas_hosted').values_list('id', flat=True), - [pet.id] + Pet.objects.prefetch_related("fleas_hosted").values_list("id", flat=True), + [pet.id], ) class UUIDPrefetchRelatedLookups(TestCase): - @classmethod def setUpTestData(cls): - house = House.objects.create(name='Redwood', address='Arcata') - room = Room.objects.create(name='Racoon', house=house) + house = House.objects.create(name="Redwood", address="Arcata") + room = Room.objects.create(name="Racoon", house=house) fleas = [Flea.objects.create(current_room=room) for i in range(3)] - pet = Pet.objects.create(name='Spooky') + pet = Pet.objects.create(name="Spooky") pet.fleas_hosted.add(*fleas) - person = Person.objects.create(name='Bob') + person = Person.objects.create(name="Bob") person.houses.add(house) person.pets.add(pet) person.fleas_hosted.add(*fleas) @@ -71,34 +69,48 @@ class UUIDPrefetchRelatedLookups(TestCase): def test_from_uuid_pk_lookup_uuid_pk_integer_pk(self): # From uuid-pk model, prefetch <uuid-pk model>.<integer-pk model>: with self.assertNumQueries(4): - spooky = Pet.objects.prefetch_related('fleas_hosted__current_room__house').get(name='Spooky') + spooky = Pet.objects.prefetch_related( + "fleas_hosted__current_room__house" + ).get(name="Spooky") with self.assertNumQueries(0): - self.assertEqual('Racoon', spooky.fleas_hosted.all()[0].current_room.name) + self.assertEqual("Racoon", spooky.fleas_hosted.all()[0].current_room.name) def test_from_uuid_pk_lookup_integer_pk2_uuid_pk2(self): # From uuid-pk model, prefetch <integer-pk model>.<integer-pk model>.<uuid-pk model>.<uuid-pk model>: with self.assertNumQueries(5): - spooky = Pet.objects.prefetch_related('people__houses__rooms__fleas').get(name='Spooky') + spooky = Pet.objects.prefetch_related("people__houses__rooms__fleas").get( + name="Spooky" + ) with self.assertNumQueries(0): - self.assertEqual(3, len(spooky.people.all()[0].houses.all()[0].rooms.all()[0].fleas.all())) + self.assertEqual( + 3, + len(spooky.people.all()[0].houses.all()[0].rooms.all()[0].fleas.all()), + ) def test_from_integer_pk_lookup_uuid_pk_integer_pk(self): # From integer-pk model, prefetch <uuid-pk model>.<integer-pk model>: with self.assertNumQueries(3): - racoon = Room.objects.prefetch_related('fleas__people_visited').get(name='Racoon') + racoon = Room.objects.prefetch_related("fleas__people_visited").get( + name="Racoon" + ) with self.assertNumQueries(0): - self.assertEqual('Bob', racoon.fleas.all()[0].people_visited.all()[0].name) + self.assertEqual("Bob", racoon.fleas.all()[0].people_visited.all()[0].name) def test_from_integer_pk_lookup_integer_pk_uuid_pk(self): # From integer-pk model, prefetch <integer-pk model>.<uuid-pk model>: with self.assertNumQueries(3): - redwood = House.objects.prefetch_related('rooms__fleas').get(name='Redwood') + redwood = House.objects.prefetch_related("rooms__fleas").get(name="Redwood") with self.assertNumQueries(0): self.assertEqual(3, len(redwood.rooms.all()[0].fleas.all())) def test_from_integer_pk_lookup_integer_pk_uuid_pk_uuid_pk(self): # From integer-pk model, prefetch <integer-pk model>.<uuid-pk model>.<uuid-pk model>: with self.assertNumQueries(4): - redwood = House.objects.prefetch_related('rooms__fleas__pets_visited').get(name='Redwood') + redwood = House.objects.prefetch_related("rooms__fleas__pets_visited").get( + name="Redwood" + ) with self.assertNumQueries(0): - self.assertEqual('Spooky', redwood.rooms.all()[0].fleas.all()[0].pets_visited.all()[0].name) + self.assertEqual( + "Spooky", + redwood.rooms.all()[0].fleas.all()[0].pets_visited.all()[0].name, + ) diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py index b6de765391..bc34bb870d 100644 --- a/tests/prefetch_related/tests.py +++ b/tests/prefetch_related/tests.py @@ -11,33 +11,53 @@ from django.test.utils import CaptureQueriesContext, ignore_warnings from django.utils.deprecation import RemovedInDjango50Warning from .models import ( - Article, Author, Author2, AuthorAddress, AuthorWithAge, Bio, Book, - Bookmark, BookReview, BookWithYear, Comment, Department, Employee, - FavoriteAuthors, House, LessonEntry, ModelIterableSubclass, Person, - Qualification, Reader, Room, TaggedItem, Teacher, WordEntry, + Article, + Author, + Author2, + AuthorAddress, + AuthorWithAge, + Bio, + Book, + Bookmark, + BookReview, + BookWithYear, + Comment, + Department, + Employee, + FavoriteAuthors, + House, + LessonEntry, + ModelIterableSubclass, + Person, + Qualification, + Reader, + Room, + TaggedItem, + Teacher, + WordEntry, ) class TestDataMixin: @classmethod def setUpTestData(cls): - cls.book1 = Book.objects.create(title='Poems') - cls.book2 = Book.objects.create(title='Jane Eyre') - cls.book3 = Book.objects.create(title='Wuthering Heights') - cls.book4 = Book.objects.create(title='Sense and Sensibility') + cls.book1 = Book.objects.create(title="Poems") + cls.book2 = Book.objects.create(title="Jane Eyre") + cls.book3 = Book.objects.create(title="Wuthering Heights") + cls.book4 = Book.objects.create(title="Sense and Sensibility") - cls.author1 = Author.objects.create(name='Charlotte', first_book=cls.book1) - cls.author2 = Author.objects.create(name='Anne', first_book=cls.book1) - cls.author3 = Author.objects.create(name='Emily', first_book=cls.book1) - cls.author4 = Author.objects.create(name='Jane', first_book=cls.book4) + cls.author1 = Author.objects.create(name="Charlotte", first_book=cls.book1) + cls.author2 = Author.objects.create(name="Anne", first_book=cls.book1) + cls.author3 = Author.objects.create(name="Emily", first_book=cls.book1) + cls.author4 = Author.objects.create(name="Jane", first_book=cls.book4) cls.book1.authors.add(cls.author1, cls.author2, cls.author3) cls.book2.authors.add(cls.author1) cls.book3.authors.add(cls.author3) cls.book4.authors.add(cls.author4) - cls.reader1 = Reader.objects.create(name='Amy') - cls.reader2 = Reader.objects.create(name='Belinda') + cls.reader1 = Reader.objects.create(name="Amy") + cls.reader2 = Reader.objects.create(name="Belinda") cls.reader1.books_read.add(cls.book1, cls.book4) cls.reader2.books_read.add(cls.book2, cls.book4) @@ -45,44 +65,54 @@ class TestDataMixin: class PrefetchRelatedTests(TestDataMixin, TestCase): def assertWhereContains(self, sql, needle): - where_idx = sql.index('WHERE') + where_idx = sql.index("WHERE") self.assertEqual( - sql.count(str(needle), where_idx), 1, - msg="WHERE clause doesn't contain %s, actual SQL: %s" % (needle, sql[where_idx:]) + sql.count(str(needle), where_idx), + 1, + msg="WHERE clause doesn't contain %s, actual SQL: %s" + % (needle, sql[where_idx:]), ) def test_m2m_forward(self): with self.assertNumQueries(2): - lists = [list(b.authors.all()) for b in Book.objects.prefetch_related('authors')] + lists = [ + list(b.authors.all()) for b in Book.objects.prefetch_related("authors") + ] normal_lists = [list(b.authors.all()) for b in Book.objects.all()] self.assertEqual(lists, normal_lists) def test_m2m_reverse(self): with self.assertNumQueries(2): - lists = [list(a.books.all()) for a in Author.objects.prefetch_related('books')] + lists = [ + list(a.books.all()) for a in Author.objects.prefetch_related("books") + ] normal_lists = [list(a.books.all()) for a in Author.objects.all()] self.assertEqual(lists, normal_lists) def test_foreignkey_forward(self): with self.assertNumQueries(2): - books = [a.first_book for a in Author.objects.prefetch_related('first_book')] + books = [ + a.first_book for a in Author.objects.prefetch_related("first_book") + ] normal_books = [a.first_book for a in Author.objects.all()] self.assertEqual(books, normal_books) def test_foreignkey_reverse(self): with self.assertNumQueries(2): - [list(b.first_time_authors.all()) - for b in Book.objects.prefetch_related('first_time_authors')] + [ + list(b.first_time_authors.all()) + for b in Book.objects.prefetch_related("first_time_authors") + ] self.assertSequenceEqual(self.book2.authors.all(), [self.author1]) def test_onetoone_reverse_no_match(self): # Regression for #17439 with self.assertNumQueries(2): - book = Book.objects.prefetch_related('bookwithyear').all()[0] + book = Book.objects.prefetch_related("bookwithyear").all()[0] with self.assertNumQueries(0): with self.assertRaises(BookWithYear.DoesNotExist): book.bookwithyear @@ -92,43 +122,49 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): A model (Bio) with a OneToOneField primary key (author) that references a non-pk field (name) on the related model (Author) is prefetchable. """ - Bio.objects.bulk_create([ - Bio(author=self.author1), - Bio(author=self.author2), - Bio(author=self.author3), - ]) + Bio.objects.bulk_create( + [ + Bio(author=self.author1), + Bio(author=self.author2), + Bio(author=self.author3), + ] + ) authors = Author.objects.filter( name__in=[self.author1, self.author2, self.author3], - ).prefetch_related('bio') + ).prefetch_related("bio") with self.assertNumQueries(2): for author in authors: self.assertEqual(author.name, author.bio.author.name) def test_survives_clone(self): with self.assertNumQueries(2): - [list(b.first_time_authors.all()) - for b in Book.objects.prefetch_related('first_time_authors').exclude(id=1000)] + [ + list(b.first_time_authors.all()) + for b in Book.objects.prefetch_related("first_time_authors").exclude( + id=1000 + ) + ] def test_len(self): with self.assertNumQueries(2): - qs = Book.objects.prefetch_related('first_time_authors') + qs = Book.objects.prefetch_related("first_time_authors") len(qs) [list(b.first_time_authors.all()) for b in qs] def test_bool(self): with self.assertNumQueries(2): - qs = Book.objects.prefetch_related('first_time_authors') + qs = Book.objects.prefetch_related("first_time_authors") bool(qs) [list(b.first_time_authors.all()) for b in qs] def test_count(self): with self.assertNumQueries(2): - qs = Book.objects.prefetch_related('first_time_authors') + qs = Book.objects.prefetch_related("first_time_authors") [b.first_time_authors.count() for b in qs] def test_exists(self): with self.assertNumQueries(2): - qs = Book.objects.prefetch_related('first_time_authors') + qs = Book.objects.prefetch_related("first_time_authors") [b.first_time_authors.exists() for b in qs] def test_in_and_prefetch_related(self): @@ -138,52 +174,61 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): reads from QuerySet iteration in 70679243d1786e03557c28929f9762a119e3ac14. """ - qs = Book.objects.prefetch_related('first_time_authors') + qs = Book.objects.prefetch_related("first_time_authors") self.assertIn(qs[0], qs) def test_clear(self): with self.assertNumQueries(5): - with_prefetch = Author.objects.prefetch_related('books') + with_prefetch = Author.objects.prefetch_related("books") without_prefetch = with_prefetch.prefetch_related(None) [list(a.books.all()) for a in without_prefetch] def test_m2m_then_m2m(self): """A m2m can be followed through another m2m.""" with self.assertNumQueries(3): - qs = Author.objects.prefetch_related('books__read_by') - lists = [[[str(r) for r in b.read_by.all()] - for b in a.books.all()] - for a in qs] - self.assertEqual(lists, [ - [["Amy"], ["Belinda"]], # Charlotte - Poems, Jane Eyre - [["Amy"]], # Anne - Poems - [["Amy"], []], # Emily - Poems, Wuthering Heights - [["Amy", "Belinda"]], # Jane - Sense and Sense - ]) + qs = Author.objects.prefetch_related("books__read_by") + lists = [ + [[str(r) for r in b.read_by.all()] for b in a.books.all()] for a in qs + ] + self.assertEqual( + lists, + [ + [["Amy"], ["Belinda"]], # Charlotte - Poems, Jane Eyre + [["Amy"]], # Anne - Poems + [["Amy"], []], # Emily - Poems, Wuthering Heights + [["Amy", "Belinda"]], # Jane - Sense and Sense + ], + ) def test_overriding_prefetch(self): with self.assertNumQueries(3): - qs = Author.objects.prefetch_related('books', 'books__read_by') - lists = [[[str(r) for r in b.read_by.all()] - for b in a.books.all()] - for a in qs] - self.assertEqual(lists, [ - [["Amy"], ["Belinda"]], # Charlotte - Poems, Jane Eyre - [["Amy"]], # Anne - Poems - [["Amy"], []], # Emily - Poems, Wuthering Heights - [["Amy", "Belinda"]], # Jane - Sense and Sense - ]) + qs = Author.objects.prefetch_related("books", "books__read_by") + lists = [ + [[str(r) for r in b.read_by.all()] for b in a.books.all()] for a in qs + ] + self.assertEqual( + lists, + [ + [["Amy"], ["Belinda"]], # Charlotte - Poems, Jane Eyre + [["Amy"]], # Anne - Poems + [["Amy"], []], # Emily - Poems, Wuthering Heights + [["Amy", "Belinda"]], # Jane - Sense and Sense + ], + ) with self.assertNumQueries(3): - qs = Author.objects.prefetch_related('books__read_by', 'books') - lists = [[[str(r) for r in b.read_by.all()] - for b in a.books.all()] - for a in qs] - self.assertEqual(lists, [ - [["Amy"], ["Belinda"]], # Charlotte - Poems, Jane Eyre - [["Amy"]], # Anne - Poems - [["Amy"], []], # Emily - Poems, Wuthering Heights - [["Amy", "Belinda"]], # Jane - Sense and Sense - ]) + qs = Author.objects.prefetch_related("books__read_by", "books") + lists = [ + [[str(r) for r in b.read_by.all()] for b in a.books.all()] for a in qs + ] + self.assertEqual( + lists, + [ + [["Amy"], ["Belinda"]], # Charlotte - Poems, Jane Eyre + [["Amy"]], # Anne - Poems + [["Amy"], []], # Emily - Poems, Wuthering Heights + [["Amy", "Belinda"]], # Jane - Sense and Sense + ], + ) def test_get(self): """ @@ -191,7 +236,9 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): """ # Need a double with self.assertNumQueries(3): - author = Author.objects.prefetch_related('books__read_by').get(name="Charlotte") + author = Author.objects.prefetch_related("books__read_by").get( + name="Charlotte" + ) lists = [[str(r) for r in b.read_by.all()] for b in author.books.all()] self.assertEqual(lists, [["Amy"], ["Belinda"]]) # Poems, Jane Eyre @@ -201,9 +248,10 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): doesn't have many objects. """ with self.assertNumQueries(2): - qs = Author.objects.select_related('first_book').prefetch_related('first_book__read_by') - lists = [[str(r) for r in a.first_book.read_by.all()] - for a in qs] + qs = Author.objects.select_related("first_book").prefetch_related( + "first_book__read_by" + ) + lists = [[str(r) for r in a.first_book.read_by.all()] for a in qs] self.assertEqual(lists, [["Amy"], ["Amy"], ["Amy"], ["Amy", "Belinda"]]) def test_reverse_one_to_one_then_m2m(self): @@ -211,7 +259,7 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): A m2m relation can be followed after going through the select_related reverse of an o2o. """ - qs = Author.objects.prefetch_related('bio__books').select_related('bio') + qs = Author.objects.prefetch_related("bio__books").select_related("bio") with self.assertNumQueries(1): list(qs.all()) @@ -221,7 +269,7 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): list(qs.all()) def test_attribute_error(self): - qs = Reader.objects.all().prefetch_related('books_read__xyz') + qs = Reader.objects.all().prefetch_related("books_read__xyz") msg = ( "Cannot find 'xyz' on Book object, 'books_read__xyz' " "is an invalid parameter to prefetch_related()" @@ -229,10 +277,10 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): with self.assertRaisesMessage(AttributeError, msg) as cm: list(qs) - self.assertIn('prefetch_related', str(cm.exception)) + self.assertIn("prefetch_related", str(cm.exception)) def test_invalid_final_lookup(self): - qs = Book.objects.prefetch_related('authors__name') + qs = Book.objects.prefetch_related("authors__name") msg = ( "'authors__name' does not resolve to an item that supports " "prefetching - this is an invalid parameter to prefetch_related()." @@ -240,57 +288,61 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): with self.assertRaisesMessage(ValueError, msg) as cm: list(qs) - self.assertIn('prefetch_related', str(cm.exception)) + self.assertIn("prefetch_related", str(cm.exception)) self.assertIn("name", str(cm.exception)) def test_prefetch_eq(self): - prefetch_1 = Prefetch('authors', queryset=Author.objects.all()) - prefetch_2 = Prefetch('books', queryset=Book.objects.all()) + prefetch_1 = Prefetch("authors", queryset=Author.objects.all()) + prefetch_2 = Prefetch("books", queryset=Book.objects.all()) self.assertEqual(prefetch_1, prefetch_1) self.assertEqual(prefetch_1, mock.ANY) self.assertNotEqual(prefetch_1, prefetch_2) def test_forward_m2m_to_attr_conflict(self): - msg = 'to_attr=authors conflicts with a field on the Book model.' + msg = "to_attr=authors conflicts with a field on the Book model." authors = Author.objects.all() with self.assertRaisesMessage(ValueError, msg): - list(Book.objects.prefetch_related( - Prefetch('authors', queryset=authors, to_attr='authors'), - )) + list( + Book.objects.prefetch_related( + Prefetch("authors", queryset=authors, to_attr="authors"), + ) + ) # Without the ValueError, an author was deleted due to the implicit # save of the relation assignment. self.assertEqual(self.book1.authors.count(), 3) def test_reverse_m2m_to_attr_conflict(self): - msg = 'to_attr=books conflicts with a field on the Author model.' - poems = Book.objects.filter(title='Poems') + msg = "to_attr=books conflicts with a field on the Author model." + poems = Book.objects.filter(title="Poems") with self.assertRaisesMessage(ValueError, msg): - list(Author.objects.prefetch_related( - Prefetch('books', queryset=poems, to_attr='books'), - )) + list( + Author.objects.prefetch_related( + Prefetch("books", queryset=poems, to_attr="books"), + ) + ) # Without the ValueError, a book was deleted due to the implicit # save of reverse relation assignment. self.assertEqual(self.author1.books.count(), 2) def test_m2m_then_reverse_fk_object_ids(self): with CaptureQueriesContext(connection) as queries: - list(Book.objects.prefetch_related('authors__addresses')) + list(Book.objects.prefetch_related("authors__addresses")) - sql = queries[-1]['sql'] + sql = queries[-1]["sql"] self.assertWhereContains(sql, self.author1.name) def test_m2m_then_m2m_object_ids(self): with CaptureQueriesContext(connection) as queries: - list(Book.objects.prefetch_related('authors__favorite_authors')) + list(Book.objects.prefetch_related("authors__favorite_authors")) - sql = queries[-1]['sql'] + sql = queries[-1]["sql"] self.assertWhereContains(sql, self.author1.name) def test_m2m_then_reverse_one_to_one_object_ids(self): with CaptureQueriesContext(connection) as queries: - list(Book.objects.prefetch_related('authors__authorwithage')) + list(Book.objects.prefetch_related("authors__authorwithage")) - sql = queries[-1]['sql'] + sql = queries[-1]["sql"] self.assertWhereContains(sql, self.author1.id) def test_filter_deferred(self): @@ -299,11 +351,11 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): reverse m2o relations until necessary. """ add_q = Query.add_q - for relation in ['authors', 'first_time_authors']: + for relation in ["authors", "first_time_authors"]: with self.subTest(relation=relation): with mock.patch.object( Query, - 'add_q', + "add_q", autospec=True, side_effect=lambda self, q: add_q(self, q), ) as add_q_mock: @@ -311,17 +363,17 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): self.assertEqual(add_q_mock.call_count, 1) def test_named_values_list(self): - qs = Author.objects.prefetch_related('books') + qs = Author.objects.prefetch_related("books") self.assertCountEqual( - [value.name for value in qs.values_list('name', named=True)], - ['Anne', 'Charlotte', 'Emily', 'Jane'], + [value.name for value in qs.values_list("name", named=True)], + ["Anne", "Charlotte", "Emily", "Jane"], ) def test_m2m_prefetching_iterator_with_chunks(self): with self.assertNumQueries(3): authors = [ b.authors.first() - for b in Book.objects.prefetch_related('authors').iterator(chunk_size=2) + for b in Book.objects.prefetch_related("authors").iterator(chunk_size=2) ] self.assertEqual( authors, @@ -334,7 +386,7 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): with self.assertNumQueries(5): authors = [ b.authors.first() - for b in Book.objects.prefetch_related('authors').iterator() + for b in Book.objects.prefetch_related("authors").iterator() ] self.assertEqual( authors, @@ -343,41 +395,43 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): def test_m2m_prefetching_iterator_without_chunks_warning(self): msg = ( - 'Using QuerySet.iterator() after prefetch_related() without ' - 'specifying chunk_size is deprecated.' + "Using QuerySet.iterator() after prefetch_related() without " + "specifying chunk_size is deprecated." ) with self.assertWarnsMessage(RemovedInDjango50Warning, msg): - Book.objects.prefetch_related('authors').iterator() + Book.objects.prefetch_related("authors").iterator() class RawQuerySetTests(TestDataMixin, TestCase): def test_basic(self): with self.assertNumQueries(2): books = Book.objects.raw( - "SELECT * FROM prefetch_related_book WHERE id = %s", - (self.book1.id,) - ).prefetch_related('authors') + "SELECT * FROM prefetch_related_book WHERE id = %s", (self.book1.id,) + ).prefetch_related("authors") book1 = list(books)[0] with self.assertNumQueries(0): - self.assertCountEqual(book1.authors.all(), [self.author1, self.author2, self.author3]) + self.assertCountEqual( + book1.authors.all(), [self.author1, self.author2, self.author3] + ) def test_prefetch_before_raw(self): with self.assertNumQueries(2): - books = Book.objects.prefetch_related('authors').raw( - "SELECT * FROM prefetch_related_book WHERE id = %s", - (self.book1.id,) + books = Book.objects.prefetch_related("authors").raw( + "SELECT * FROM prefetch_related_book WHERE id = %s", (self.book1.id,) ) book1 = list(books)[0] with self.assertNumQueries(0): - self.assertCountEqual(book1.authors.all(), [self.author1, self.author2, self.author3]) + self.assertCountEqual( + book1.authors.all(), [self.author1, self.author2, self.author3] + ) def test_clear(self): with self.assertNumQueries(5): with_prefetch = Author.objects.raw( "SELECT * FROM prefetch_related_author" - ).prefetch_related('books') + ).prefetch_related("books") without_prefetch = with_prefetch.prefetch_related(None) [list(a.books.all()) for a in without_prefetch] @@ -392,7 +446,7 @@ class CustomPrefetchTests(TestCase): """ ret_val = [] - if hasattr(obj_iter, 'all'): + if hasattr(obj_iter, "all"): obj_iter = obj_iter.all() try: @@ -416,49 +470,58 @@ class CustomPrefetchTests(TestCase): @classmethod def setUpTestData(cls): - cls.person1 = Person.objects.create(name='Joe') - cls.person2 = Person.objects.create(name='Mary') + cls.person1 = Person.objects.create(name="Joe") + cls.person2 = Person.objects.create(name="Mary") # Set main_room for each house before creating the next one for # databases where supports_nullable_unique_constraints is False. - cls.house1 = House.objects.create(name='House 1', address='123 Main St', owner=cls.person1) - cls.room1_1 = Room.objects.create(name='Dining room', house=cls.house1) - cls.room1_2 = Room.objects.create(name='Lounge', house=cls.house1) - cls.room1_3 = Room.objects.create(name='Kitchen', house=cls.house1) + cls.house1 = House.objects.create( + name="House 1", address="123 Main St", owner=cls.person1 + ) + cls.room1_1 = Room.objects.create(name="Dining room", house=cls.house1) + cls.room1_2 = Room.objects.create(name="Lounge", house=cls.house1) + cls.room1_3 = Room.objects.create(name="Kitchen", house=cls.house1) cls.house1.main_room = cls.room1_1 cls.house1.save() cls.person1.houses.add(cls.house1) - cls.house2 = House.objects.create(name='House 2', address='45 Side St', owner=cls.person1) - cls.room2_1 = Room.objects.create(name='Dining room', house=cls.house2) - cls.room2_2 = Room.objects.create(name='Lounge', house=cls.house2) - cls.room2_3 = Room.objects.create(name='Kitchen', house=cls.house2) + cls.house2 = House.objects.create( + name="House 2", address="45 Side St", owner=cls.person1 + ) + cls.room2_1 = Room.objects.create(name="Dining room", house=cls.house2) + cls.room2_2 = Room.objects.create(name="Lounge", house=cls.house2) + cls.room2_3 = Room.objects.create(name="Kitchen", house=cls.house2) cls.house2.main_room = cls.room2_1 cls.house2.save() cls.person1.houses.add(cls.house2) - cls.house3 = House.objects.create(name='House 3', address='6 Downing St', owner=cls.person2) - cls.room3_1 = Room.objects.create(name='Dining room', house=cls.house3) - cls.room3_2 = Room.objects.create(name='Lounge', house=cls.house3) - cls.room3_3 = Room.objects.create(name='Kitchen', house=cls.house3) + cls.house3 = House.objects.create( + name="House 3", address="6 Downing St", owner=cls.person2 + ) + cls.room3_1 = Room.objects.create(name="Dining room", house=cls.house3) + cls.room3_2 = Room.objects.create(name="Lounge", house=cls.house3) + cls.room3_3 = Room.objects.create(name="Kitchen", house=cls.house3) cls.house3.main_room = cls.room3_1 cls.house3.save() cls.person2.houses.add(cls.house3) - cls.house4 = House.objects.create(name='house 4', address="7 Regents St", owner=cls.person2) - cls.room4_1 = Room.objects.create(name='Dining room', house=cls.house4) - cls.room4_2 = Room.objects.create(name='Lounge', house=cls.house4) - cls.room4_3 = Room.objects.create(name='Kitchen', house=cls.house4) + cls.house4 = House.objects.create( + name="house 4", address="7 Regents St", owner=cls.person2 + ) + cls.room4_1 = Room.objects.create(name="Dining room", house=cls.house4) + cls.room4_2 = Room.objects.create(name="Lounge", house=cls.house4) + cls.room4_3 = Room.objects.create(name="Kitchen", house=cls.house4) cls.house4.main_room = cls.room4_1 cls.house4.save() cls.person2.houses.add(cls.house4) def test_traverse_qs(self): - qs = Person.objects.prefetch_related('houses') - related_objs_normal = [list(p.houses.all()) for p in qs], - related_objs_from_traverse = [[inner[0] for inner in o[1]] - for o in self.traverse_qs(qs, [['houses']])] + qs = Person.objects.prefetch_related("houses") + related_objs_normal = ([list(p.houses.all()) for p in qs],) + related_objs_from_traverse = [ + [inner[0] for inner in o[1]] for o in self.traverse_qs(qs, [["houses"]]) + ] self.assertEqual(related_objs_normal, (related_objs_from_traverse,)) def test_ambiguous(self): @@ -472,10 +535,10 @@ class CustomPrefetchTests(TestCase): with self.assertRaisesMessage(ValueError, msg): self.traverse_qs( Person.objects.prefetch_related( - 'houses__rooms', - Prefetch('houses', queryset=House.objects.all()), + "houses__rooms", + Prefetch("houses", queryset=House.objects.all()), ), - [['houses', 'rooms']], + [["houses", "rooms"]], ) # Ambiguous: Lookup houses_lst doesn't yet exist when performing houses_lst__rooms. @@ -486,45 +549,47 @@ class CustomPrefetchTests(TestCase): with self.assertRaisesMessage(AttributeError, msg): self.traverse_qs( Person.objects.prefetch_related( - 'houses_lst__rooms', - Prefetch('houses', queryset=House.objects.all(), to_attr='houses_lst') + "houses_lst__rooms", + Prefetch( + "houses", queryset=House.objects.all(), to_attr="houses_lst" + ), ), - [['houses', 'rooms']] + [["houses", "rooms"]], ) # Not ambiguous. self.traverse_qs( - Person.objects.prefetch_related('houses__rooms', 'houses'), - [['houses', 'rooms']] + Person.objects.prefetch_related("houses__rooms", "houses"), + [["houses", "rooms"]], ) self.traverse_qs( Person.objects.prefetch_related( - 'houses__rooms', - Prefetch('houses', queryset=House.objects.all(), to_attr='houses_lst') + "houses__rooms", + Prefetch("houses", queryset=House.objects.all(), to_attr="houses_lst"), ), - [['houses', 'rooms']] + [["houses", "rooms"]], ) def test_m2m(self): # Control lookups. with self.assertNumQueries(2): lst1 = self.traverse_qs( - Person.objects.prefetch_related('houses'), - [['houses']] + Person.objects.prefetch_related("houses"), [["houses"]] ) # Test lookups. with self.assertNumQueries(2): lst2 = self.traverse_qs( - Person.objects.prefetch_related(Prefetch('houses')), - [['houses']] + Person.objects.prefetch_related(Prefetch("houses")), [["houses"]] ) self.assertEqual(lst1, lst2) with self.assertNumQueries(2): lst2 = self.traverse_qs( - Person.objects.prefetch_related(Prefetch('houses', to_attr='houses_lst')), - [['houses_lst']] + Person.objects.prefetch_related( + Prefetch("houses", to_attr="houses_lst") + ), + [["houses_lst"]], ) self.assertEqual(lst1, lst2) @@ -532,21 +597,21 @@ class CustomPrefetchTests(TestCase): # Control lookups. with self.assertNumQueries(2): lst1 = self.traverse_qs( - House.objects.prefetch_related('occupants'), - [['occupants']] + House.objects.prefetch_related("occupants"), [["occupants"]] ) # Test lookups. with self.assertNumQueries(2): lst2 = self.traverse_qs( - House.objects.prefetch_related(Prefetch('occupants')), - [['occupants']] + House.objects.prefetch_related(Prefetch("occupants")), [["occupants"]] ) self.assertEqual(lst1, lst2) with self.assertNumQueries(2): lst2 = self.traverse_qs( - House.objects.prefetch_related(Prefetch('occupants', to_attr='occupants_lst')), - [['occupants_lst']] + House.objects.prefetch_related( + Prefetch("occupants", to_attr="occupants_lst") + ), + [["occupants_lst"]], ) self.assertEqual(lst1, lst2) @@ -554,21 +619,23 @@ class CustomPrefetchTests(TestCase): # Control lookups. with self.assertNumQueries(3): lst1 = self.traverse_qs( - Room.objects.prefetch_related('house__occupants'), - [['house', 'occupants']] + Room.objects.prefetch_related("house__occupants"), + [["house", "occupants"]], ) # Test lookups. with self.assertNumQueries(3): lst2 = self.traverse_qs( - Room.objects.prefetch_related(Prefetch('house__occupants')), - [['house', 'occupants']] + Room.objects.prefetch_related(Prefetch("house__occupants")), + [["house", "occupants"]], ) self.assertEqual(lst1, lst2) with self.assertNumQueries(3): lst2 = self.traverse_qs( - Room.objects.prefetch_related(Prefetch('house__occupants', to_attr='occupants_lst')), - [['house', 'occupants_lst']] + Room.objects.prefetch_related( + Prefetch("house__occupants", to_attr="occupants_lst") + ), + [["house", "occupants_lst"]], ) self.assertEqual(lst1, lst2) @@ -579,18 +646,20 @@ class CustomPrefetchTests(TestCase): # Control lookups. with self.assertNumQueries(3): lst1 = self.traverse_qs( - TaggedItem.objects.filter(tag='houses').prefetch_related('content_object__rooms'), - [['content_object', 'rooms']] + TaggedItem.objects.filter(tag="houses").prefetch_related( + "content_object__rooms" + ), + [["content_object", "rooms"]], ) # Test lookups. with self.assertNumQueries(3): lst2 = self.traverse_qs( TaggedItem.objects.prefetch_related( - Prefetch('content_object'), - Prefetch('content_object__rooms', to_attr='rooms_lst') + Prefetch("content_object"), + Prefetch("content_object__rooms", to_attr="rooms_lst"), ), - [['content_object', 'rooms_lst']] + [["content_object", "rooms_lst"]], ) self.assertEqual(lst1, lst2) @@ -598,60 +667,68 @@ class CustomPrefetchTests(TestCase): # Control lookups. with self.assertNumQueries(3): lst1 = self.traverse_qs( - Person.objects.prefetch_related('houses', 'houses__rooms'), - [['houses', 'rooms']] + Person.objects.prefetch_related("houses", "houses__rooms"), + [["houses", "rooms"]], ) # Test lookups. with self.assertNumQueries(3): lst2 = self.traverse_qs( - Person.objects.prefetch_related(Prefetch('houses'), 'houses__rooms'), - [['houses', 'rooms']] + Person.objects.prefetch_related(Prefetch("houses"), "houses__rooms"), + [["houses", "rooms"]], ) self.assertEqual(lst1, lst2) with self.assertNumQueries(3): lst2 = self.traverse_qs( - Person.objects.prefetch_related(Prefetch('houses'), Prefetch('houses__rooms')), - [['houses', 'rooms']] + Person.objects.prefetch_related( + Prefetch("houses"), Prefetch("houses__rooms") + ), + [["houses", "rooms"]], ) self.assertEqual(lst1, lst2) with self.assertNumQueries(3): lst2 = self.traverse_qs( - Person.objects.prefetch_related(Prefetch('houses', to_attr='houses_lst'), 'houses_lst__rooms'), - [['houses_lst', 'rooms']] + Person.objects.prefetch_related( + Prefetch("houses", to_attr="houses_lst"), "houses_lst__rooms" + ), + [["houses_lst", "rooms"]], ) self.assertEqual(lst1, lst2) with self.assertNumQueries(3): lst2 = self.traverse_qs( Person.objects.prefetch_related( - Prefetch('houses', to_attr='houses_lst'), - Prefetch('houses_lst__rooms', to_attr='rooms_lst') + Prefetch("houses", to_attr="houses_lst"), + Prefetch("houses_lst__rooms", to_attr="rooms_lst"), ), - [['houses_lst', 'rooms_lst']] + [["houses_lst", "rooms_lst"]], ) self.assertEqual(lst1, lst2) def test_generic_rel(self): - bookmark = Bookmark.objects.create(url='http://www.djangoproject.com/') - TaggedItem.objects.create(content_object=bookmark, tag='django') - TaggedItem.objects.create(content_object=bookmark, favorite=bookmark, tag='python') + bookmark = Bookmark.objects.create(url="http://www.djangoproject.com/") + TaggedItem.objects.create(content_object=bookmark, tag="django") + TaggedItem.objects.create( + content_object=bookmark, favorite=bookmark, tag="python" + ) # Control lookups. with self.assertNumQueries(4): lst1 = self.traverse_qs( - Bookmark.objects.prefetch_related('tags', 'tags__content_object', 'favorite_tags'), - [['tags', 'content_object'], ['favorite_tags']] + Bookmark.objects.prefetch_related( + "tags", "tags__content_object", "favorite_tags" + ), + [["tags", "content_object"], ["favorite_tags"]], ) # Test lookups. with self.assertNumQueries(4): lst2 = self.traverse_qs( Bookmark.objects.prefetch_related( - Prefetch('tags', to_attr='tags_lst'), - Prefetch('tags_lst__content_object'), - Prefetch('favorite_tags'), + Prefetch("tags", to_attr="tags_lst"), + Prefetch("tags_lst__content_object"), + Prefetch("favorite_tags"), ), - [['tags_lst', 'content_object'], ['favorite_tags']] + [["tags_lst", "content_object"], ["favorite_tags"]], ) self.assertEqual(lst1, lst2) @@ -660,21 +737,21 @@ class CustomPrefetchTests(TestCase): with self.assertNumQueries(5): lst1 = self.traverse_qs( Person.objects.prefetch_related( - 'houses__rooms', - 'primary_house__occupants__houses', + "houses__rooms", + "primary_house__occupants__houses", ), - [['primary_house', 'occupants', 'houses']] + [["primary_house", "occupants", "houses"]], ) # Test lookups. with self.assertNumQueries(5): lst2 = self.traverse_qs( Person.objects.prefetch_related( - 'houses__rooms', - Prefetch('primary_house__occupants', to_attr='occupants_lst'), - 'primary_house__occupants_lst__houses', + "houses__rooms", + Prefetch("primary_house__occupants", to_attr="occupants_lst"), + "primary_house__occupants_lst__houses", ), - [['primary_house', 'occupants_lst', 'houses']] + [["primary_house", "occupants_lst", "houses"]], ) self.assertEqual(lst1, lst2) @@ -683,34 +760,39 @@ class CustomPrefetchTests(TestCase): with self.assertNumQueries(4): lst1 = self.traverse_qs( Person.objects.prefetch_related( - 'houses', - 'all_houses__occupants__houses', + "houses", + "all_houses__occupants__houses", ), - [['all_houses', 'occupants', 'houses']] + [["all_houses", "occupants", "houses"]], ) # Test lookups. with self.assertNumQueries(4): lst2 = self.traverse_qs( Person.objects.prefetch_related( - 'houses', - Prefetch('all_houses__occupants', to_attr='occupants_lst'), - 'all_houses__occupants_lst__houses', + "houses", + Prefetch("all_houses__occupants", to_attr="occupants_lst"), + "all_houses__occupants_lst__houses", ), - [['all_houses', 'occupants_lst', 'houses']] + [["all_houses", "occupants_lst", "houses"]], ) self.assertEqual(lst1, lst2) def test_custom_qs(self): # Test basic. with self.assertNumQueries(2): - lst1 = list(Person.objects.prefetch_related('houses')) + lst1 = list(Person.objects.prefetch_related("houses")) with self.assertNumQueries(2): - lst2 = list(Person.objects.prefetch_related( - Prefetch('houses', queryset=House.objects.all(), to_attr='houses_lst'))) + lst2 = list( + Person.objects.prefetch_related( + Prefetch( + "houses", queryset=House.objects.all(), to_attr="houses_lst" + ) + ) + ) self.assertEqual( - self.traverse_qs(lst1, [['houses']]), - self.traverse_qs(lst2, [['houses_lst']]) + self.traverse_qs(lst1, [["houses"]]), + self.traverse_qs(lst2, [["houses_lst"]]), ) # Test queryset filtering. @@ -718,9 +800,11 @@ class CustomPrefetchTests(TestCase): lst2 = list( Person.objects.prefetch_related( Prefetch( - 'houses', - queryset=House.objects.filter(pk__in=[self.house1.pk, self.house3.pk]), - to_attr='houses_lst', + "houses", + queryset=House.objects.filter( + pk__in=[self.house1.pk, self.house3.pk] + ), + to_attr="houses_lst", ) ) ) @@ -731,35 +815,52 @@ class CustomPrefetchTests(TestCase): # Test flattened. with self.assertNumQueries(3): - lst1 = list(Person.objects.prefetch_related('houses__rooms')) + lst1 = list(Person.objects.prefetch_related("houses__rooms")) with self.assertNumQueries(3): - lst2 = list(Person.objects.prefetch_related( - Prefetch('houses__rooms', queryset=Room.objects.all(), to_attr='rooms_lst'))) + lst2 = list( + Person.objects.prefetch_related( + Prefetch( + "houses__rooms", + queryset=Room.objects.all(), + to_attr="rooms_lst", + ) + ) + ) self.assertEqual( - self.traverse_qs(lst1, [['houses', 'rooms']]), - self.traverse_qs(lst2, [['houses', 'rooms_lst']]) + self.traverse_qs(lst1, [["houses", "rooms"]]), + self.traverse_qs(lst2, [["houses", "rooms_lst"]]), ) # Test inner select_related. with self.assertNumQueries(3): - lst1 = list(Person.objects.prefetch_related('houses__owner')) + lst1 = list(Person.objects.prefetch_related("houses__owner")) with self.assertNumQueries(2): - lst2 = list(Person.objects.prefetch_related( - Prefetch('houses', queryset=House.objects.select_related('owner')))) + lst2 = list( + Person.objects.prefetch_related( + Prefetch("houses", queryset=House.objects.select_related("owner")) + ) + ) self.assertEqual( - self.traverse_qs(lst1, [['houses', 'owner']]), - self.traverse_qs(lst2, [['houses', 'owner']]) + self.traverse_qs(lst1, [["houses", "owner"]]), + self.traverse_qs(lst2, [["houses", "owner"]]), ) # Test inner prefetch. inner_rooms_qs = Room.objects.filter(pk__in=[self.room1_1.pk, self.room1_2.pk]) houses_qs_prf = House.objects.prefetch_related( - Prefetch('rooms', queryset=inner_rooms_qs, to_attr='rooms_lst')) + Prefetch("rooms", queryset=inner_rooms_qs, to_attr="rooms_lst") + ) with self.assertNumQueries(4): - lst2 = list(Person.objects.prefetch_related( - Prefetch('houses', queryset=houses_qs_prf.filter(pk=self.house1.pk), to_attr='houses_lst'), - Prefetch('houses_lst__rooms_lst__main_room_of') - )) + lst2 = list( + Person.objects.prefetch_related( + Prefetch( + "houses", + queryset=houses_qs_prf.filter(pk=self.house1.pk), + to_attr="houses_lst", + ), + Prefetch("houses_lst__rooms_lst__main_room_of"), + ) + ) self.assertEqual(len(lst2[0].houses_lst[0].rooms_lst), 2) self.assertEqual(lst2[0].houses_lst[0].rooms_lst[0], self.room1_1) @@ -768,65 +869,101 @@ class CustomPrefetchTests(TestCase): self.assertEqual(len(lst2[1].houses_lst), 0) # Test ForwardManyToOneDescriptor. - houses = House.objects.select_related('owner') + houses = House.objects.select_related("owner") with self.assertNumQueries(6): - rooms = Room.objects.all().prefetch_related('house') - lst1 = self.traverse_qs(rooms, [['house', 'owner']]) + rooms = Room.objects.all().prefetch_related("house") + lst1 = self.traverse_qs(rooms, [["house", "owner"]]) with self.assertNumQueries(2): - rooms = Room.objects.all().prefetch_related(Prefetch('house', queryset=houses.all())) - lst2 = self.traverse_qs(rooms, [['house', 'owner']]) + rooms = Room.objects.all().prefetch_related( + Prefetch("house", queryset=houses.all()) + ) + lst2 = self.traverse_qs(rooms, [["house", "owner"]]) self.assertEqual(lst1, lst2) with self.assertNumQueries(2): - houses = House.objects.select_related('owner') - rooms = Room.objects.all().prefetch_related(Prefetch('house', queryset=houses.all(), to_attr='house_attr')) - lst2 = self.traverse_qs(rooms, [['house_attr', 'owner']]) + houses = House.objects.select_related("owner") + rooms = Room.objects.all().prefetch_related( + Prefetch("house", queryset=houses.all(), to_attr="house_attr") + ) + lst2 = self.traverse_qs(rooms, [["house_attr", "owner"]]) self.assertEqual(lst1, lst2) - room = Room.objects.all().prefetch_related( - Prefetch('house', queryset=houses.filter(address='DoesNotExist')) - ).first() + room = ( + Room.objects.all() + .prefetch_related( + Prefetch("house", queryset=houses.filter(address="DoesNotExist")) + ) + .first() + ) with self.assertRaises(ObjectDoesNotExist): - getattr(room, 'house') - room = Room.objects.all().prefetch_related( - Prefetch('house', queryset=houses.filter(address='DoesNotExist'), to_attr='house_attr') - ).first() + getattr(room, "house") + room = ( + Room.objects.all() + .prefetch_related( + Prefetch( + "house", + queryset=houses.filter(address="DoesNotExist"), + to_attr="house_attr", + ) + ) + .first() + ) self.assertIsNone(room.house_attr) - rooms = Room.objects.all().prefetch_related(Prefetch('house', queryset=House.objects.only('name'))) + rooms = Room.objects.all().prefetch_related( + Prefetch("house", queryset=House.objects.only("name")) + ) with self.assertNumQueries(2): - getattr(rooms.first().house, 'name') + getattr(rooms.first().house, "name") with self.assertNumQueries(3): - getattr(rooms.first().house, 'address') + getattr(rooms.first().house, "address") # Test ReverseOneToOneDescriptor. - houses = House.objects.select_related('owner') + houses = House.objects.select_related("owner") with self.assertNumQueries(6): - rooms = Room.objects.all().prefetch_related('main_room_of') - lst1 = self.traverse_qs(rooms, [['main_room_of', 'owner']]) + rooms = Room.objects.all().prefetch_related("main_room_of") + lst1 = self.traverse_qs(rooms, [["main_room_of", "owner"]]) with self.assertNumQueries(2): - rooms = Room.objects.all().prefetch_related(Prefetch('main_room_of', queryset=houses.all())) - lst2 = self.traverse_qs(rooms, [['main_room_of', 'owner']]) + rooms = Room.objects.all().prefetch_related( + Prefetch("main_room_of", queryset=houses.all()) + ) + lst2 = self.traverse_qs(rooms, [["main_room_of", "owner"]]) self.assertEqual(lst1, lst2) with self.assertNumQueries(2): rooms = list( Room.objects.all().prefetch_related( - Prefetch('main_room_of', queryset=houses.all(), to_attr='main_room_of_attr') + Prefetch( + "main_room_of", + queryset=houses.all(), + to_attr="main_room_of_attr", + ) ) ) - lst2 = self.traverse_qs(rooms, [['main_room_of_attr', 'owner']]) + lst2 = self.traverse_qs(rooms, [["main_room_of_attr", "owner"]]) self.assertEqual(lst1, lst2) - room = Room.objects.filter(main_room_of__isnull=False).prefetch_related( - Prefetch('main_room_of', queryset=houses.filter(address='DoesNotExist')) - ).first() + room = ( + Room.objects.filter(main_room_of__isnull=False) + .prefetch_related( + Prefetch("main_room_of", queryset=houses.filter(address="DoesNotExist")) + ) + .first() + ) with self.assertRaises(ObjectDoesNotExist): - getattr(room, 'main_room_of') - room = Room.objects.filter(main_room_of__isnull=False).prefetch_related( - Prefetch('main_room_of', queryset=houses.filter(address='DoesNotExist'), to_attr='main_room_of_attr') - ).first() + getattr(room, "main_room_of") + room = ( + Room.objects.filter(main_room_of__isnull=False) + .prefetch_related( + Prefetch( + "main_room_of", + queryset=houses.filter(address="DoesNotExist"), + to_attr="main_room_of_attr", + ) + ) + .first() + ) self.assertIsNone(room.main_room_of_attr) # The custom queryset filters should be applied to the queryset # instance returned by the manager. person = Person.objects.prefetch_related( - Prefetch('houses', queryset=House.objects.filter(name='House 1')), + Prefetch("houses", queryset=House.objects.filter(name="House 1")), ).get(pk=self.person1.pk) self.assertEqual( list(person.houses.all()), @@ -835,13 +972,13 @@ class CustomPrefetchTests(TestCase): def test_nested_prefetch_related_are_not_overwritten(self): # Regression test for #24873 - houses_2 = House.objects.prefetch_related(Prefetch('rooms')) - persons = Person.objects.prefetch_related(Prefetch('houses', queryset=houses_2)) - houses = House.objects.prefetch_related(Prefetch('occupants', queryset=persons)) + houses_2 = House.objects.prefetch_related(Prefetch("rooms")) + persons = Person.objects.prefetch_related(Prefetch("houses", queryset=houses_2)) + houses = House.objects.prefetch_related(Prefetch("occupants", queryset=persons)) list(houses) # queryset must be evaluated once to reproduce the bug. self.assertEqual( houses.all()[0].occupants.all()[0].houses.all()[1].rooms.all()[0], - self.room2_1 + self.room2_1, ) def test_nested_prefetch_related_with_duplicate_prefetcher(self): @@ -850,37 +987,41 @@ class CustomPrefetchTests(TestCase): (Person.houses here) are allowed. """ occupants = Person.objects.prefetch_related( - Prefetch('houses', to_attr='some_attr_name'), - Prefetch('houses', queryset=House.objects.prefetch_related('main_room')), + Prefetch("houses", to_attr="some_attr_name"), + Prefetch("houses", queryset=House.objects.prefetch_related("main_room")), + ) + houses = House.objects.prefetch_related( + Prefetch("occupants", queryset=occupants) ) - houses = House.objects.prefetch_related(Prefetch('occupants', queryset=occupants)) with self.assertNumQueries(5): - self.traverse_qs(list(houses), [['occupants', 'houses', 'main_room']]) + self.traverse_qs(list(houses), [["occupants", "houses", "main_room"]]) def test_values_queryset(self): - msg = 'Prefetch querysets cannot use raw(), values(), and values_list().' + msg = "Prefetch querysets cannot use raw(), values(), and values_list()." with self.assertRaisesMessage(ValueError, msg): - Prefetch('houses', House.objects.values('pk')) + Prefetch("houses", House.objects.values("pk")) with self.assertRaisesMessage(ValueError, msg): - Prefetch('houses', House.objects.values_list('pk')) + Prefetch("houses", House.objects.values_list("pk")) # That error doesn't affect managers with custom ModelIterable subclasses - self.assertIs(Teacher.objects_custom.all()._iterable_class, ModelIterableSubclass) - Prefetch('teachers', Teacher.objects_custom.all()) + self.assertIs( + Teacher.objects_custom.all()._iterable_class, ModelIterableSubclass + ) + Prefetch("teachers", Teacher.objects_custom.all()) def test_raw_queryset(self): - msg = 'Prefetch querysets cannot use raw(), values(), and values_list().' + msg = "Prefetch querysets cannot use raw(), values(), and values_list()." with self.assertRaisesMessage(ValueError, msg): - Prefetch('houses', House.objects.raw('select pk from house')) + Prefetch("houses", House.objects.raw("select pk from house")) def test_to_attr_doesnt_cache_through_attr_as_list(self): house = House.objects.prefetch_related( - Prefetch('rooms', queryset=Room.objects.all(), to_attr='to_rooms'), + Prefetch("rooms", queryset=Room.objects.all(), to_attr="to_rooms"), ).get(pk=self.house3.pk) self.assertIsInstance(house.rooms.all(), QuerySet) def test_to_attr_cached_property(self): persons = Person.objects.prefetch_related( - Prefetch('houses', House.objects.all(), to_attr='cached_all_houses'), + Prefetch("houses", House.objects.all(), to_attr="cached_all_houses"), ) for person in persons: # To bypass caching at the related descriptor level, don't use @@ -896,34 +1037,35 @@ class CustomPrefetchTests(TestCase): add_q = Query.add_q with mock.patch.object( Query, - 'add_q', + "add_q", autospec=True, side_effect=lambda self, q: add_q(self, q), ) as add_q_mock: - list(House.objects.prefetch_related( - Prefetch('occupants', queryset=Person.objects.all()) - )) + list( + House.objects.prefetch_related( + Prefetch("occupants", queryset=Person.objects.all()) + ) + ) self.assertEqual(add_q_mock.call_count, 1) class DefaultManagerTests(TestCase): - @classmethod def setUpTestData(cls): - cls.qual1 = Qualification.objects.create(name='BA') - cls.qual2 = Qualification.objects.create(name='BSci') - cls.qual3 = Qualification.objects.create(name='MA') - cls.qual4 = Qualification.objects.create(name='PhD') - - cls.teacher1 = Teacher.objects.create(name='Mr Cleese') - cls.teacher2 = Teacher.objects.create(name='Mr Idle') - cls.teacher3 = Teacher.objects.create(name='Mr Chapman') + cls.qual1 = Qualification.objects.create(name="BA") + cls.qual2 = Qualification.objects.create(name="BSci") + cls.qual3 = Qualification.objects.create(name="MA") + cls.qual4 = Qualification.objects.create(name="PhD") + + cls.teacher1 = Teacher.objects.create(name="Mr Cleese") + cls.teacher2 = Teacher.objects.create(name="Mr Idle") + cls.teacher3 = Teacher.objects.create(name="Mr Chapman") cls.teacher1.qualifications.add(cls.qual1, cls.qual2, cls.qual3, cls.qual4) cls.teacher2.qualifications.add(cls.qual1) cls.teacher3.qualifications.add(cls.qual2) - cls.dept1 = Department.objects.create(name='English') - cls.dept2 = Department.objects.create(name='Physics') + cls.dept1 = Department.objects.create(name="English") + cls.dept2 = Department.objects.create(name="Physics") cls.dept1.teachers.add(cls.teacher1, cls.teacher2) cls.dept2.teachers.add(cls.teacher1, cls.teacher3) @@ -932,18 +1074,21 @@ class DefaultManagerTests(TestCase): # When we prefetch the teachers, and force the query, we don't want # the default manager on teachers to immediately get all the related # qualifications, since this will do one query per teacher. - qs = Department.objects.prefetch_related('teachers') - depts = "".join("%s department: %s\n" % - (dept.name, ", ".join(str(t) for t in dept.teachers.all())) - for dept in qs) + qs = Department.objects.prefetch_related("teachers") + depts = "".join( + "%s department: %s\n" + % (dept.name, ", ".join(str(t) for t in dept.teachers.all())) + for dept in qs + ) - self.assertEqual(depts, - "English department: Mr Cleese (BA, BSci, MA, PhD), Mr Idle (BA)\n" - "Physics department: Mr Cleese (BA, BSci, MA, PhD), Mr Chapman (BSci)\n") + self.assertEqual( + depts, + "English department: Mr Cleese (BA, BSci, MA, PhD), Mr Idle (BA)\n" + "Physics department: Mr Cleese (BA, BSci, MA, PhD), Mr Chapman (BSci)\n", + ) class GenericRelationTests(TestCase): - @classmethod def setUpTestData(cls): book1 = Book.objects.create(title="Winnie the Pooh") @@ -969,7 +1114,7 @@ class GenericRelationTests(TestCase): # 1 for TaggedItem table, 1 for Book table, 1 for Reader table with self.assertNumQueries(3): - qs = TaggedItem.objects.prefetch_related('content_object') + qs = TaggedItem.objects.prefetch_related("content_object") list(qs) def test_prefetch_GFK_nonint_pk(self): @@ -977,20 +1122,20 @@ class GenericRelationTests(TestCase): # 1 for Comment table, 1 for Book table with self.assertNumQueries(2): - qs = Comment.objects.prefetch_related('content_object') + qs = Comment.objects.prefetch_related("content_object") [c.content_object for c in qs] def test_prefetch_GFK_uuid_pk(self): - article = Article.objects.create(name='Django') - Comment.objects.create(comment='awesome', content_object_uuid=article) - qs = Comment.objects.prefetch_related('content_object_uuid') + article = Article.objects.create(name="Django") + Comment.objects.create(comment="awesome", content_object_uuid=article) + qs = Comment.objects.prefetch_related("content_object_uuid") self.assertEqual([c.content_object_uuid for c in qs], [article]) def test_prefetch_GFK_fk_pk(self): - book = Book.objects.create(title='Poems') + book = Book.objects.create(title="Poems") book_with_year = BookWithYear.objects.create(book=book, published_year=2019) - Comment.objects.create(comment='awesome', content_object=book_with_year) - qs = Comment.objects.prefetch_related('content_object') + Comment.objects.create(comment="awesome", content_object=book_with_year) + qs = Comment.objects.prefetch_related("content_object") self.assertEqual([c.content_object for c in qs], [book_with_year]) def test_traverse_GFK(self): @@ -1012,51 +1157,63 @@ class GenericRelationTests(TestCase): with self.assertNumQueries(3): # If we limit to books, we know that they will have 'read_by' # attributes, so the following makes sense: - qs = TaggedItem.objects.filter(content_type=ct, tag='awesome').prefetch_related('content_object__read_by') - readers_of_awesome_books = {r.name for tag in qs - for r in tag.content_object.read_by.all()} + qs = TaggedItem.objects.filter( + content_type=ct, tag="awesome" + ).prefetch_related("content_object__read_by") + readers_of_awesome_books = { + r.name for tag in qs for r in tag.content_object.read_by.all() + } self.assertEqual(readers_of_awesome_books, {"me", "you", "someone"}) def test_nullable_GFK(self): - TaggedItem.objects.create(tag="awesome", content_object=self.book1, - created_by=self.reader1) + TaggedItem.objects.create( + tag="awesome", content_object=self.book1, created_by=self.reader1 + ) TaggedItem.objects.create(tag="great", content_object=self.book2) TaggedItem.objects.create(tag="rubbish", content_object=self.book3) with self.assertNumQueries(2): - result = [t.created_by for t in TaggedItem.objects.prefetch_related('created_by')] + result = [ + t.created_by for t in TaggedItem.objects.prefetch_related("created_by") + ] - self.assertEqual(result, - [t.created_by for t in TaggedItem.objects.all()]) + self.assertEqual(result, [t.created_by for t in TaggedItem.objects.all()]) def test_generic_relation(self): - bookmark = Bookmark.objects.create(url='http://www.djangoproject.com/') - TaggedItem.objects.create(content_object=bookmark, tag='django') - TaggedItem.objects.create(content_object=bookmark, tag='python') + bookmark = Bookmark.objects.create(url="http://www.djangoproject.com/") + TaggedItem.objects.create(content_object=bookmark, tag="django") + TaggedItem.objects.create(content_object=bookmark, tag="python") with self.assertNumQueries(2): - tags = [t.tag for b in Bookmark.objects.prefetch_related('tags') - for t in b.tags.all()] + tags = [ + t.tag + for b in Bookmark.objects.prefetch_related("tags") + for t in b.tags.all() + ] self.assertEqual(sorted(tags), ["django", "python"]) def test_charfield_GFK(self): - b = Bookmark.objects.create(url='http://www.djangoproject.com/') - TaggedItem.objects.create(content_object=b, tag='django') - TaggedItem.objects.create(content_object=b, favorite=b, tag='python') + b = Bookmark.objects.create(url="http://www.djangoproject.com/") + TaggedItem.objects.create(content_object=b, tag="django") + TaggedItem.objects.create(content_object=b, favorite=b, tag="python") with self.assertNumQueries(3): - bookmark = Bookmark.objects.filter(pk=b.pk).prefetch_related('tags', 'favorite_tags')[0] - self.assertEqual(sorted(i.tag for i in bookmark.tags.all()), ["django", "python"]) + bookmark = Bookmark.objects.filter(pk=b.pk).prefetch_related( + "tags", "favorite_tags" + )[0] + self.assertEqual( + sorted(i.tag for i in bookmark.tags.all()), ["django", "python"] + ) self.assertEqual([i.tag for i in bookmark.favorite_tags.all()], ["python"]) def test_custom_queryset(self): - bookmark = Bookmark.objects.create(url='http://www.djangoproject.com/') - django_tag = TaggedItem.objects.create(content_object=bookmark, tag='django') - TaggedItem.objects.create(content_object=bookmark, tag='python') + bookmark = Bookmark.objects.create(url="http://www.djangoproject.com/") + django_tag = TaggedItem.objects.create(content_object=bookmark, tag="django") + TaggedItem.objects.create(content_object=bookmark, tag="python") with self.assertNumQueries(2): bookmark = Bookmark.objects.prefetch_related( - Prefetch('tags', TaggedItem.objects.filter(tag='django')), + Prefetch("tags", TaggedItem.objects.filter(tag="django")), ).get() with self.assertNumQueries(0): @@ -1067,59 +1224,75 @@ class GenericRelationTests(TestCase): self.assertEqual(list(bookmark.tags.all()), list(bookmark.tags.all().all())) def test_deleted_GFK(self): - TaggedItem.objects.create(tag='awesome', content_object=self.book1) - TaggedItem.objects.create(tag='awesome', content_object=self.book2) + TaggedItem.objects.create(tag="awesome", content_object=self.book1) + TaggedItem.objects.create(tag="awesome", content_object=self.book2) ct = ContentType.objects.get_for_model(Book) book1_pk = self.book1.pk self.book1.delete() with self.assertNumQueries(2): - qs = TaggedItem.objects.filter(tag='awesome').prefetch_related('content_object') + qs = TaggedItem.objects.filter(tag="awesome").prefetch_related( + "content_object" + ) result = [ (tag.object_id, tag.content_type_id, tag.content_object) for tag in qs ] - self.assertEqual(result, [ - (book1_pk, ct.pk, None), - (self.book2.pk, ct.pk, self.book2), - ]) + self.assertEqual( + result, + [ + (book1_pk, ct.pk, None), + (self.book2.pk, ct.pk, self.book2), + ], + ) class MultiTableInheritanceTest(TestCase): - @classmethod def setUpTestData(cls): - cls.book1 = BookWithYear.objects.create(title='Poems', published_year=2010) - cls.book2 = BookWithYear.objects.create(title='More poems', published_year=2011) - cls.author1 = AuthorWithAge.objects.create(name='Jane', first_book=cls.book1, age=50) - cls.author2 = AuthorWithAge.objects.create(name='Tom', first_book=cls.book1, age=49) - cls.author3 = AuthorWithAge.objects.create(name='Robert', first_book=cls.book2, age=48) - cls.author_address = AuthorAddress.objects.create(author=cls.author1, address='SomeStreet 1') + cls.book1 = BookWithYear.objects.create(title="Poems", published_year=2010) + cls.book2 = BookWithYear.objects.create(title="More poems", published_year=2011) + cls.author1 = AuthorWithAge.objects.create( + name="Jane", first_book=cls.book1, age=50 + ) + cls.author2 = AuthorWithAge.objects.create( + name="Tom", first_book=cls.book1, age=49 + ) + cls.author3 = AuthorWithAge.objects.create( + name="Robert", first_book=cls.book2, age=48 + ) + cls.author_address = AuthorAddress.objects.create( + author=cls.author1, address="SomeStreet 1" + ) cls.book2.aged_authors.add(cls.author2, cls.author3) - cls.br1 = BookReview.objects.create(book=cls.book1, notes='review book1') - cls.br2 = BookReview.objects.create(book=cls.book2, notes='review book2') + cls.br1 = BookReview.objects.create(book=cls.book1, notes="review book1") + cls.br2 = BookReview.objects.create(book=cls.book2, notes="review book2") def test_foreignkey(self): with self.assertNumQueries(2): - qs = AuthorWithAge.objects.prefetch_related('addresses') - addresses = [[str(address) for address in obj.addresses.all()] for obj in qs] + qs = AuthorWithAge.objects.prefetch_related("addresses") + addresses = [ + [str(address) for address in obj.addresses.all()] for obj in qs + ] self.assertEqual(addresses, [[str(self.author_address)], [], []]) def test_foreignkey_to_inherited(self): with self.assertNumQueries(2): - qs = BookReview.objects.prefetch_related('book') + qs = BookReview.objects.prefetch_related("book") titles = [obj.book.title for obj in qs] self.assertEqual(titles, ["Poems", "More poems"]) def test_m2m_to_inheriting_model(self): - qs = AuthorWithAge.objects.prefetch_related('books_with_year') + qs = AuthorWithAge.objects.prefetch_related("books_with_year") with self.assertNumQueries(2): - lst = [[str(book) for book in author.books_with_year.all()] for author in qs] + lst = [ + [str(book) for book in author.books_with_year.all()] for author in qs + ] qs = AuthorWithAge.objects.all() lst2 = [[str(book) for book in author.books_with_year.all()] for author in qs] self.assertEqual(lst, lst2) - qs = BookWithYear.objects.prefetch_related('aged_authors') + qs = BookWithYear.objects.prefetch_related("aged_authors") with self.assertNumQueries(2): lst = [[str(author) for author in book.aged_authors.all()] for book in qs] qs = BookWithYear.objects.all() @@ -1128,62 +1301,70 @@ class MultiTableInheritanceTest(TestCase): def test_parent_link_prefetch(self): with self.assertNumQueries(2): - [a.author for a in AuthorWithAge.objects.prefetch_related('author')] + [a.author for a in AuthorWithAge.objects.prefetch_related("author")] @override_settings(DEBUG=True) def test_child_link_prefetch(self): with self.assertNumQueries(2): - authors = [a.authorwithage for a in Author.objects.prefetch_related('authorwithage')] + authors = [ + a.authorwithage + for a in Author.objects.prefetch_related("authorwithage") + ] # Regression for #18090: the prefetching query must include an IN clause. # Note that on Oracle the table name is upper case in the generated SQL, # thus the .lower() call. - self.assertIn('authorwithage', connection.queries[-1]['sql'].lower()) - self.assertIn(' IN ', connection.queries[-1]['sql']) + self.assertIn("authorwithage", connection.queries[-1]["sql"].lower()) + self.assertIn(" IN ", connection.queries[-1]["sql"]) self.assertEqual(authors, [a.authorwithage for a in Author.objects.all()]) class ForeignKeyToFieldTest(TestCase): - @classmethod def setUpTestData(cls): - cls.book = Book.objects.create(title='Poems') - cls.author1 = Author.objects.create(name='Jane', first_book=cls.book) - cls.author2 = Author.objects.create(name='Tom', first_book=cls.book) - cls.author3 = Author.objects.create(name='Robert', first_book=cls.book) - cls.author_address = AuthorAddress.objects.create(author=cls.author1, address='SomeStreet 1') + cls.book = Book.objects.create(title="Poems") + cls.author1 = Author.objects.create(name="Jane", first_book=cls.book) + cls.author2 = Author.objects.create(name="Tom", first_book=cls.book) + cls.author3 = Author.objects.create(name="Robert", first_book=cls.book) + cls.author_address = AuthorAddress.objects.create( + author=cls.author1, address="SomeStreet 1" + ) FavoriteAuthors.objects.create(author=cls.author1, likes_author=cls.author2) FavoriteAuthors.objects.create(author=cls.author2, likes_author=cls.author3) FavoriteAuthors.objects.create(author=cls.author3, likes_author=cls.author1) def test_foreignkey(self): with self.assertNumQueries(2): - qs = Author.objects.prefetch_related('addresses') - addresses = [[str(address) for address in obj.addresses.all()] - for obj in qs] + qs = Author.objects.prefetch_related("addresses") + addresses = [ + [str(address) for address in obj.addresses.all()] for obj in qs + ] self.assertEqual(addresses, [[str(self.author_address)], [], []]) def test_m2m(self): with self.assertNumQueries(3): - qs = Author.objects.all().prefetch_related('favorite_authors', 'favors_me') - favorites = [( - [str(i_like) for i_like in author.favorite_authors.all()], - [str(likes_me) for likes_me in author.favors_me.all()] - ) for author in qs] + qs = Author.objects.all().prefetch_related("favorite_authors", "favors_me") + favorites = [ + ( + [str(i_like) for i_like in author.favorite_authors.all()], + [str(likes_me) for likes_me in author.favors_me.all()], + ) + for author in qs + ] self.assertEqual( favorites, [ ([str(self.author2)], [str(self.author3)]), ([str(self.author3)], [str(self.author1)]), - ([str(self.author1)], [str(self.author2)]) - ] + ([str(self.author1)], [str(self.author2)]), + ], ) def test_m2m_manager_reused(self): author = Author.objects.prefetch_related( - 'favorite_authors', - 'favors_me', + "favorite_authors", + "favors_me", ).first() self.assertIs(author.favorite_authors, author.favorite_authors) self.assertIs(author.favors_me, author.favors_me) @@ -1197,37 +1378,37 @@ class LookupOrderingTest(TestCase): @classmethod def setUpTestData(cls): - person1 = Person.objects.create(name='Joe') - person2 = Person.objects.create(name='Mary') + person1 = Person.objects.create(name="Joe") + person2 = Person.objects.create(name="Mary") # Set main_room for each house before creating the next one for # databases where supports_nullable_unique_constraints is False. - house1 = House.objects.create(address='123 Main St') - room1_1 = Room.objects.create(name='Dining room', house=house1) - Room.objects.create(name='Lounge', house=house1) - Room.objects.create(name='Kitchen', house=house1) + house1 = House.objects.create(address="123 Main St") + room1_1 = Room.objects.create(name="Dining room", house=house1) + Room.objects.create(name="Lounge", house=house1) + Room.objects.create(name="Kitchen", house=house1) house1.main_room = room1_1 house1.save() person1.houses.add(house1) - house2 = House.objects.create(address='45 Side St') - room2_1 = Room.objects.create(name='Dining room', house=house2) - Room.objects.create(name='Lounge', house=house2) + house2 = House.objects.create(address="45 Side St") + room2_1 = Room.objects.create(name="Dining room", house=house2) + Room.objects.create(name="Lounge", house=house2) house2.main_room = room2_1 house2.save() person1.houses.add(house2) - house3 = House.objects.create(address='6 Downing St') - room3_1 = Room.objects.create(name='Dining room', house=house3) - Room.objects.create(name='Lounge', house=house3) - Room.objects.create(name='Kitchen', house=house3) + house3 = House.objects.create(address="6 Downing St") + room3_1 = Room.objects.create(name="Dining room", house=house3) + Room.objects.create(name="Lounge", house=house3) + Room.objects.create(name="Kitchen", house=house3) house3.main_room = room3_1 house3.save() person2.houses.add(house3) - house4 = House.objects.create(address='7 Regents St') - room4_1 = Room.objects.create(name='Dining room', house=house4) - Room.objects.create(name='Lounge', house=house4) + house4 = House.objects.create(address="7 Regents St") + room4_1 = Room.objects.create(name="Dining room", house=house4) + Room.objects.create(name="Lounge", house=house4) house4.main_room = room4_1 house4.save() person2.houses.add(house4) @@ -1236,13 +1417,13 @@ class LookupOrderingTest(TestCase): with self.assertNumQueries(4): # The following two queries must be done in the same order as written, # otherwise 'primary_house' will cause non-prefetched lookups - qs = Person.objects.prefetch_related('houses__rooms', - 'primary_house__occupants') + qs = Person.objects.prefetch_related( + "houses__rooms", "primary_house__occupants" + ) [list(p.primary_house.occupants.all()) for p in qs] class NullableTest(TestCase): - @classmethod def setUpTestData(cls): boss = Employee.objects.create(name="Peter") @@ -1253,24 +1434,30 @@ class NullableTest(TestCase): # Because we use select_related() for 'boss', it doesn't need to be # prefetched, but we can still traverse it although it contains some nulls with self.assertNumQueries(2): - qs = Employee.objects.select_related('boss').prefetch_related('boss__serfs') - co_serfs = [list(e.boss.serfs.all()) if e.boss is not None else [] - for e in qs] + qs = Employee.objects.select_related("boss").prefetch_related("boss__serfs") + co_serfs = [ + list(e.boss.serfs.all()) if e.boss is not None else [] for e in qs + ] - qs2 = Employee.objects.select_related('boss') - co_serfs2 = [list(e.boss.serfs.all()) if e.boss is not None else [] for e in qs2] + qs2 = Employee.objects.select_related("boss") + co_serfs2 = [ + list(e.boss.serfs.all()) if e.boss is not None else [] for e in qs2 + ] self.assertEqual(co_serfs, co_serfs2) def test_prefetch_nullable(self): # One for main employee, one for boss, one for serfs with self.assertNumQueries(3): - qs = Employee.objects.prefetch_related('boss__serfs') - co_serfs = [list(e.boss.serfs.all()) if e.boss is not None else [] - for e in qs] + qs = Employee.objects.prefetch_related("boss__serfs") + co_serfs = [ + list(e.boss.serfs.all()) if e.boss is not None else [] for e in qs + ] qs2 = Employee.objects.all() - co_serfs2 = [list(e.boss.serfs.all()) if e.boss is not None else [] for e in qs2] + co_serfs2 = [ + list(e.boss.serfs.all()) if e.boss is not None else [] for e in qs2 + ] self.assertEqual(co_serfs, co_serfs2) @@ -1283,17 +1470,19 @@ class NullableTest(TestCase): boss2 = Employee.objects.create(name="Jack") with self.assertNumQueries(2): # Prefetch is done and it does not cause any errors. - bulk = Employee.objects.prefetch_related('serfs').in_bulk([boss1.pk, boss2.pk]) + bulk = Employee.objects.prefetch_related("serfs").in_bulk( + [boss1.pk, boss2.pk] + ) for b in bulk.values(): list(b.serfs.all()) class MultiDbTests(TestCase): - databases = {'default', 'other'} + databases = {"default", "other"} def test_using_is_honored_m2m(self): - B = Book.objects.using('other') - A = Author.objects.using('other') + B = Book.objects.using("other") + A = Author.objects.using("other") book1 = B.create(title="Poems") book2 = B.create(title="Jane Eyre") book3 = B.create(title="Wuthering Heights") @@ -1310,32 +1499,40 @@ class MultiDbTests(TestCase): book4.authors.add(author4) # Forward - qs1 = B.prefetch_related('authors') - with self.assertNumQueries(2, using='other'): - books = "".join("%s (%s)\n" % - (book.title, ", ".join(a.name for a in book.authors.all())) - for book in qs1) - self.assertEqual(books, - "Poems (Charlotte, Anne, Emily)\n" - "Jane Eyre (Charlotte)\n" - "Wuthering Heights (Emily)\n" - "Sense and Sensibility (Jane)\n") + qs1 = B.prefetch_related("authors") + with self.assertNumQueries(2, using="other"): + books = "".join( + "%s (%s)\n" + % (book.title, ", ".join(a.name for a in book.authors.all())) + for book in qs1 + ) + self.assertEqual( + books, + "Poems (Charlotte, Anne, Emily)\n" + "Jane Eyre (Charlotte)\n" + "Wuthering Heights (Emily)\n" + "Sense and Sensibility (Jane)\n", + ) # Reverse - qs2 = A.prefetch_related('books') - with self.assertNumQueries(2, using='other'): - authors = "".join("%s: %s\n" % - (author.name, ", ".join(b.title for b in author.books.all())) - for author in qs2) - self.assertEqual(authors, - "Charlotte: Poems, Jane Eyre\n" - "Anne: Poems\n" - "Emily: Poems, Wuthering Heights\n" - "Jane: Sense and Sensibility\n") + qs2 = A.prefetch_related("books") + with self.assertNumQueries(2, using="other"): + authors = "".join( + "%s: %s\n" + % (author.name, ", ".join(b.title for b in author.books.all())) + for author in qs2 + ) + self.assertEqual( + authors, + "Charlotte: Poems, Jane Eyre\n" + "Anne: Poems\n" + "Emily: Poems, Wuthering Heights\n" + "Jane: Sense and Sensibility\n", + ) def test_using_is_honored_fkey(self): - B = Book.objects.using('other') - A = Author.objects.using('other') + B = Book.objects.using("other") + A = Author.objects.using("other") book1 = B.create(title="Poems") book2 = B.create(title="Sense and Sensibility") @@ -1343,43 +1540,49 @@ class MultiDbTests(TestCase): A.create(name="Jane Austen", first_book=book2) # Forward - with self.assertNumQueries(2, using='other'): - books = ", ".join(a.first_book.title for a in A.prefetch_related('first_book')) + with self.assertNumQueries(2, using="other"): + books = ", ".join( + a.first_book.title for a in A.prefetch_related("first_book") + ) self.assertEqual("Poems, Sense and Sensibility", books) # Reverse - with self.assertNumQueries(2, using='other'): - books = "".join("%s (%s)\n" % - (b.title, ", ".join(a.name for a in b.first_time_authors.all())) - for b in B.prefetch_related('first_time_authors')) + with self.assertNumQueries(2, using="other"): + books = "".join( + "%s (%s)\n" + % (b.title, ", ".join(a.name for a in b.first_time_authors.all())) + for b in B.prefetch_related("first_time_authors") + ) self.assertEqual( books, "Poems (Charlotte Bronte)\nSense and Sensibility (Jane Austen)\n", ) def test_using_is_honored_inheritance(self): - B = BookWithYear.objects.using('other') - A = AuthorWithAge.objects.using('other') + B = BookWithYear.objects.using("other") + A = AuthorWithAge.objects.using("other") book1 = B.create(title="Poems", published_year=2010) B.create(title="More poems", published_year=2011) - A.create(name='Jane', first_book=book1, age=50) - A.create(name='Tom', first_book=book1, age=49) + A.create(name="Jane", first_book=book1, age=50) + A.create(name="Tom", first_book=book1, age=49) # parent link - with self.assertNumQueries(2, using='other'): - authors = ", ".join(a.author.name for a in A.prefetch_related('author')) + with self.assertNumQueries(2, using="other"): + authors = ", ".join(a.author.name for a in A.prefetch_related("author")) self.assertEqual(authors, "Jane, Tom") # child link - with self.assertNumQueries(2, using='other'): - ages = ", ".join(str(a.authorwithage.age) for a in A.prefetch_related('authorwithage')) + with self.assertNumQueries(2, using="other"): + ages = ", ".join( + str(a.authorwithage.age) for a in A.prefetch_related("authorwithage") + ) self.assertEqual(ages, "50, 49") def test_using_is_honored_custom_qs(self): - B = Book.objects.using('other') - A = Author.objects.using('other') + B = Book.objects.using("other") + A = Author.objects.using("other") book1 = B.create(title="Poems") book2 = B.create(title="Sense and Sensibility") @@ -1387,35 +1590,45 @@ class MultiDbTests(TestCase): A.create(name="Jane Austen", first_book=book2) # Implicit hinting - with self.assertNumQueries(2, using='other'): - prefetch = Prefetch('first_time_authors', queryset=Author.objects.all()) - books = "".join("%s (%s)\n" % - (b.title, ", ".join(a.name for a in b.first_time_authors.all())) - for b in B.prefetch_related(prefetch)) + with self.assertNumQueries(2, using="other"): + prefetch = Prefetch("first_time_authors", queryset=Author.objects.all()) + books = "".join( + "%s (%s)\n" + % (b.title, ", ".join(a.name for a in b.first_time_authors.all())) + for b in B.prefetch_related(prefetch) + ) self.assertEqual( books, "Poems (Charlotte Bronte)\nSense and Sensibility (Jane Austen)\n", ) # Explicit using on the same db. - with self.assertNumQueries(2, using='other'): - prefetch = Prefetch('first_time_authors', queryset=Author.objects.using('other')) - books = "".join("%s (%s)\n" % - (b.title, ", ".join(a.name for a in b.first_time_authors.all())) - for b in B.prefetch_related(prefetch)) + with self.assertNumQueries(2, using="other"): + prefetch = Prefetch( + "first_time_authors", queryset=Author.objects.using("other") + ) + books = "".join( + "%s (%s)\n" + % (b.title, ", ".join(a.name for a in b.first_time_authors.all())) + for b in B.prefetch_related(prefetch) + ) self.assertEqual( books, "Poems (Charlotte Bronte)\nSense and Sensibility (Jane Austen)\n", ) # Explicit using on a different db. - with self.assertNumQueries(1, using='default'), self.assertNumQueries(1, using='other'): - prefetch = Prefetch('first_time_authors', queryset=Author.objects.using('default')) - books = "".join("%s (%s)\n" % - (b.title, ", ".join(a.name for a in b.first_time_authors.all())) - for b in B.prefetch_related(prefetch)) - self.assertEqual(books, - "Poems ()\n" - "Sense and Sensibility ()\n") + with self.assertNumQueries(1, using="default"), self.assertNumQueries( + 1, using="other" + ): + prefetch = Prefetch( + "first_time_authors", queryset=Author.objects.using("default") + ) + books = "".join( + "%s (%s)\n" + % (b.title, ", ".join(a.name for a in b.first_time_authors.all())) + for b in B.prefetch_related(prefetch) + ) + self.assertEqual(books, "Poems ()\n" "Sense and Sensibility ()\n") class Ticket19607Tests(TestCase): @@ -1424,36 +1637,40 @@ class Ticket19607Tests(TestCase): LessonEntry.objects.bulk_create( LessonEntry(id=id_, name1=name1, name2=name2) for id_, name1, name2 in [ - (1, 'einfach', 'simple'), - (2, 'schwierig', 'difficult'), + (1, "einfach", "simple"), + (2, "schwierig", "difficult"), ] ) WordEntry.objects.bulk_create( WordEntry(id=id_, lesson_entry_id=lesson_entry_id, name=name) for id_, lesson_entry_id, name in [ - (1, 1, 'einfach'), - (2, 1, 'simple'), - (3, 2, 'schwierig'), - (4, 2, 'difficult'), + (1, 1, "einfach"), + (2, 1, "simple"), + (3, 2, "schwierig"), + (4, 2, "difficult"), ] ) def test_bug(self): - list(WordEntry.objects.prefetch_related('lesson_entry', 'lesson_entry__wordentry_set')) + list( + WordEntry.objects.prefetch_related( + "lesson_entry", "lesson_entry__wordentry_set" + ) + ) class Ticket21410Tests(TestCase): @classmethod def setUpTestData(cls): - book1 = Book.objects.create(title='Poems') - book2 = Book.objects.create(title='Jane Eyre') - book3 = Book.objects.create(title='Wuthering Heights') - book4 = Book.objects.create(title='Sense and Sensibility') + book1 = Book.objects.create(title="Poems") + book2 = Book.objects.create(title="Jane Eyre") + book3 = Book.objects.create(title="Wuthering Heights") + book4 = Book.objects.create(title="Sense and Sensibility") - author1 = Author2.objects.create(name='Charlotte', first_book=book1) - author2 = Author2.objects.create(name='Anne', first_book=book1) - author3 = Author2.objects.create(name='Emily', first_book=book1) - author4 = Author2.objects.create(name='Jane', first_book=book4) + author1 = Author2.objects.create(name="Charlotte", first_book=book1) + author2 = Author2.objects.create(name="Anne", first_book=book1) + author3 = Author2.objects.create(name="Emily", first_book=book1) + author4 = Author2.objects.create(name="Jane", first_book=book4) author1.favorite_books.add(book1, book2, book3) author2.favorite_books.add(book1) @@ -1461,11 +1678,10 @@ class Ticket21410Tests(TestCase): author4.favorite_books.add(book3) def test_bug(self): - list(Author2.objects.prefetch_related('first_book', 'favorite_books')) + list(Author2.objects.prefetch_related("first_book", "favorite_books")) class Ticket21760Tests(TestCase): - @classmethod def setUpTestData(cls): cls.rooms = [] @@ -1479,9 +1695,9 @@ class Ticket21760Tests(TestCase): house.save() def test_bug(self): - prefetcher = get_prefetcher(self.rooms[0], 'house', 'house')[0] + prefetcher = get_prefetcher(self.rooms[0], "house", "house")[0] queryset = prefetcher.get_prefetch_queryset(list(Room.objects.all()))[0] - self.assertNotIn(' JOIN ', str(queryset.query)) + self.assertNotIn(" JOIN ", str(queryset.query)) class DirectPrefetchedObjectCacheReuseTests(TestCase): @@ -1502,20 +1718,22 @@ class DirectPrefetchedObjectCacheReuseTests(TestCase): @classmethod def setUpTestData(cls): cls.book1, cls.book2 = [ - Book.objects.create(title='book1'), - Book.objects.create(title='book2'), + Book.objects.create(title="book1"), + Book.objects.create(title="book2"), ] cls.author11, cls.author12, cls.author21 = [ - Author.objects.create(first_book=cls.book1, name='Author11'), - Author.objects.create(first_book=cls.book1, name='Author12'), - Author.objects.create(first_book=cls.book2, name='Author21'), + Author.objects.create(first_book=cls.book1, name="Author11"), + Author.objects.create(first_book=cls.book1, name="Author12"), + Author.objects.create(first_book=cls.book2, name="Author21"), ] cls.author1_address1, cls.author1_address2, cls.author2_address1 = [ - AuthorAddress.objects.create(author=cls.author11, address='Happy place'), - AuthorAddress.objects.create(author=cls.author12, address='Haunted house'), - AuthorAddress.objects.create(author=cls.author21, address='Happy place'), + AuthorAddress.objects.create(author=cls.author11, address="Happy place"), + AuthorAddress.objects.create(author=cls.author12, address="Haunted house"), + AuthorAddress.objects.create(author=cls.author21, address="Happy place"), ] - cls.bookwithyear1 = BookWithYear.objects.create(title='Poems', published_year=2010) + cls.bookwithyear1 = BookWithYear.objects.create( + title="Poems", published_year=2010 + ) cls.bookreview1 = BookReview.objects.create(book=cls.bookwithyear1) def test_detect_is_fetched(self): @@ -1524,15 +1742,13 @@ class DirectPrefetchedObjectCacheReuseTests(TestCase): lookup. """ with self.assertNumQueries(3): - books = Book.objects.filter( - title__in=['book1', 'book2'], - ).prefetch_related( + books = Book.objects.filter(title__in=["book1", "book2"],).prefetch_related( Prefetch( - 'first_time_authors', + "first_time_authors", Author.objects.prefetch_related( Prefetch( - 'addresses', - AuthorAddress.objects.filter(address='Happy place'), + "addresses", + AuthorAddress.objects.filter(address="Happy place"), ) ), ), @@ -1540,47 +1756,57 @@ class DirectPrefetchedObjectCacheReuseTests(TestCase): book1, book2 = list(books) with self.assertNumQueries(0): - self.assertSequenceEqual(book1.first_time_authors.all(), [self.author11, self.author12]) + self.assertSequenceEqual( + book1.first_time_authors.all(), [self.author11, self.author12] + ) self.assertSequenceEqual(book2.first_time_authors.all(), [self.author21]) - self.assertSequenceEqual(book1.first_time_authors.all()[0].addresses.all(), [self.author1_address1]) - self.assertSequenceEqual(book1.first_time_authors.all()[1].addresses.all(), []) - self.assertSequenceEqual(book2.first_time_authors.all()[0].addresses.all(), [self.author2_address1]) + self.assertSequenceEqual( + book1.first_time_authors.all()[0].addresses.all(), + [self.author1_address1], + ) + self.assertSequenceEqual( + book1.first_time_authors.all()[1].addresses.all(), [] + ) + self.assertSequenceEqual( + book2.first_time_authors.all()[0].addresses.all(), + [self.author2_address1], + ) self.assertEqual( - list(book1.first_time_authors.all()), list(book1.first_time_authors.all().all()) + list(book1.first_time_authors.all()), + list(book1.first_time_authors.all().all()), ) self.assertEqual( - list(book2.first_time_authors.all()), list(book2.first_time_authors.all().all()) + list(book2.first_time_authors.all()), + list(book2.first_time_authors.all().all()), ) self.assertEqual( list(book1.first_time_authors.all()[0].addresses.all()), - list(book1.first_time_authors.all()[0].addresses.all().all()) + list(book1.first_time_authors.all()[0].addresses.all().all()), ) self.assertEqual( list(book1.first_time_authors.all()[1].addresses.all()), - list(book1.first_time_authors.all()[1].addresses.all().all()) + list(book1.first_time_authors.all()[1].addresses.all().all()), ) self.assertEqual( list(book2.first_time_authors.all()[0].addresses.all()), - list(book2.first_time_authors.all()[0].addresses.all().all()) + list(book2.first_time_authors.all()[0].addresses.all().all()), ) def test_detect_is_fetched_with_to_attr(self): with self.assertNumQueries(3): - books = Book.objects.filter( - title__in=['book1', 'book2'], - ).prefetch_related( + books = Book.objects.filter(title__in=["book1", "book2"],).prefetch_related( Prefetch( - 'first_time_authors', + "first_time_authors", Author.objects.prefetch_related( Prefetch( - 'addresses', - AuthorAddress.objects.filter(address='Happy place'), - to_attr='happy_place', + "addresses", + AuthorAddress.objects.filter(address="Happy place"), + to_attr="happy_place", ) ), - to_attr='first_authors', + to_attr="first_authors", ), ) book1, book2 = list(books) @@ -1589,29 +1815,37 @@ class DirectPrefetchedObjectCacheReuseTests(TestCase): self.assertEqual(book1.first_authors, [self.author11, self.author12]) self.assertEqual(book2.first_authors, [self.author21]) - self.assertEqual(book1.first_authors[0].happy_place, [self.author1_address1]) + self.assertEqual( + book1.first_authors[0].happy_place, [self.author1_address1] + ) self.assertEqual(book1.first_authors[1].happy_place, []) - self.assertEqual(book2.first_authors[0].happy_place, [self.author2_address1]) + self.assertEqual( + book2.first_authors[0].happy_place, [self.author2_address1] + ) def test_prefetch_reverse_foreign_key(self): with self.assertNumQueries(2): - bookwithyear1, = BookWithYear.objects.prefetch_related('bookreview_set') + (bookwithyear1,) = BookWithYear.objects.prefetch_related("bookreview_set") with self.assertNumQueries(0): - self.assertCountEqual(bookwithyear1.bookreview_set.all(), [self.bookreview1]) + self.assertCountEqual( + bookwithyear1.bookreview_set.all(), [self.bookreview1] + ) with self.assertNumQueries(0): - prefetch_related_objects([bookwithyear1], 'bookreview_set') + prefetch_related_objects([bookwithyear1], "bookreview_set") def test_add_clears_prefetched_objects(self): bookwithyear = BookWithYear.objects.get(pk=self.bookwithyear1.pk) - prefetch_related_objects([bookwithyear], 'bookreview_set') + prefetch_related_objects([bookwithyear], "bookreview_set") self.assertCountEqual(bookwithyear.bookreview_set.all(), [self.bookreview1]) new_review = BookReview.objects.create() bookwithyear.bookreview_set.add(new_review) - self.assertCountEqual(bookwithyear.bookreview_set.all(), [self.bookreview1, new_review]) + self.assertCountEqual( + bookwithyear.bookreview_set.all(), [self.bookreview1, new_review] + ) def test_remove_clears_prefetched_objects(self): bookwithyear = BookWithYear.objects.get(pk=self.bookwithyear1.pk) - prefetch_related_objects([bookwithyear], 'bookreview_set') + prefetch_related_objects([bookwithyear], "bookreview_set") self.assertCountEqual(bookwithyear.bookreview_set.all(), [self.bookreview1]) bookwithyear.bookreview_set.remove(self.bookreview1) self.assertCountEqual(bookwithyear.bookreview_set.all(), []) @@ -1620,10 +1854,14 @@ class DirectPrefetchedObjectCacheReuseTests(TestCase): class ReadPrefetchedObjectsCacheTests(TestCase): @classmethod def setUpTestData(cls): - cls.book1 = Book.objects.create(title='Les confessions Volume I') - cls.book2 = Book.objects.create(title='Candide') - cls.author1 = AuthorWithAge.objects.create(name='Rousseau', first_book=cls.book1, age=70) - cls.author2 = AuthorWithAge.objects.create(name='Voltaire', first_book=cls.book2, age=65) + cls.book1 = Book.objects.create(title="Les confessions Volume I") + cls.book2 = Book.objects.create(title="Candide") + cls.author1 = AuthorWithAge.objects.create( + name="Rousseau", first_book=cls.book1, age=70 + ) + cls.author2 = AuthorWithAge.objects.create( + name="Voltaire", first_book=cls.book2, age=65 + ) cls.book1.authors.add(cls.author1) cls.book2.authors.add(cls.author2) FavoriteAuthors.objects.create(author=cls.author1, likes_author=cls.author2) @@ -1637,12 +1875,12 @@ class ReadPrefetchedObjectsCacheTests(TestCase): """ authors = AuthorWithAge.objects.prefetch_related( Prefetch( - 'author', + "author", queryset=Author.objects.prefetch_related( # Results are saved in the RelatedManager's cache # (_prefetched_objects_cache) and do not replace the # RelatedManager on Author instances (favorite_authors) - Prefetch('favorite_authors__first_book'), + Prefetch("favorite_authors__first_book"), ), ), ) @@ -1654,8 +1892,8 @@ class ReadPrefetchedObjectsCacheTests(TestCase): class NestedPrefetchTests(TestCase): @classmethod def setUpTestData(cls): - house = House.objects.create(name='Big house', address='123 Main St') - cls.room = Room.objects.create(name='Kitchen', house=house) + house = House.objects.create(name="Big house", address="123 Main St") + cls.room = Room.objects.create(name="Kitchen", house=house) def test_nested_prefetch_is_not_overwritten_by_related_object(self): """ @@ -1664,10 +1902,13 @@ class NestedPrefetchTests(TestCase): related to a set of parent objects and the child queryset itself specifies a prefetch back to the parent. """ - queryset = House.objects.only('name').prefetch_related( - Prefetch('rooms', queryset=Room.objects.prefetch_related( - Prefetch('house', queryset=House.objects.only('address')), - )), + queryset = House.objects.only("name").prefetch_related( + Prefetch( + "rooms", + queryset=Room.objects.prefetch_related( + Prefetch("house", queryset=House.objects.only("address")), + ), + ), ) with self.assertNumQueries(3): house = queryset.first() |