diff options
| author | Adam Johnson <me@adamj.eu> | 2025-04-14 15:12:28 +0100 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-10-16 14:52:22 -0400 |
| commit | 6dc9b04018032dccbb5ad8347f7ddf4341316166 (patch) | |
| tree | da87f218b3992788d5804c552edffd270c030b7a /tests | |
| parent | 821619aa8771ef211c4c4922001efdf914201ca3 (diff) | |
Refs #28586 -- Copied fetch modes to related objects.
This change ensures that behavior and performance remain consistent when
traversing relationships.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/foreign_object/tests.py | 37 | ||||
| -rw-r--r-- | tests/generic_relations/tests.py | 32 | ||||
| -rw-r--r-- | tests/many_to_many/tests.py | 41 | ||||
| -rw-r--r-- | tests/many_to_one/tests.py | 49 | ||||
| -rw-r--r-- | tests/model_inheritance_regress/tests.py | 17 | ||||
| -rw-r--r-- | tests/one_to_one/tests.py | 38 | ||||
| -rw-r--r-- | tests/prefetch_related/tests.py | 30 | ||||
| -rw-r--r-- | tests/select_related/tests.py | 32 |
8 files changed, 274 insertions, 2 deletions
diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py index 09fb47e771..233c596885 100644 --- a/tests/foreign_object/tests.py +++ b/tests/foreign_object/tests.py @@ -5,6 +5,7 @@ from operator import attrgetter from django.core.exceptions import FieldError, ValidationError from django.db import connection, models +from django.db.models import FETCH_PEERS from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature from django.test.utils import CaptureQueriesContext, isolate_apps from django.utils import translation @@ -603,6 +604,42 @@ class MultiColumnFKTests(TestCase): [m4], ) + def test_fetch_mode_copied_forward_fetching_one(self): + person = Person.objects.fetch_mode(FETCH_PEERS).get(pk=self.bob.pk) + self.assertEqual(person._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + person.person_country._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_forward_fetching_many(self): + people = list(Person.objects.fetch_mode(FETCH_PEERS)) + person = people[0] + self.assertEqual(person._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + person.person_country._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_one(self): + country = Country.objects.fetch_mode(FETCH_PEERS).get(pk=self.usa.pk) + self.assertEqual(country._state.fetch_mode, FETCH_PEERS) + person = country.person_set.get(pk=self.bob.pk) + self.assertEqual( + person._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_many(self): + countries = list(Country.objects.fetch_mode(FETCH_PEERS)) + country = countries[0] + self.assertEqual(country._state.fetch_mode, FETCH_PEERS) + person = country.person_set.earliest("pk") + self.assertEqual( + person._state.fetch_mode, + FETCH_PEERS, + ) + class TestModelCheckTests(SimpleTestCase): @isolate_apps("foreign_object") diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py index 3de243d7b8..dceb8f4bae 100644 --- a/tests/generic_relations/tests.py +++ b/tests/generic_relations/tests.py @@ -813,7 +813,6 @@ class GenericRelationsTests(TestCase): self.assertEqual(quartz_tag.content_object, self.quartz) def test_fetch_mode_raise(self): - TaggedItem.objects.create(tag="lion", content_object=self.lion) tag = TaggedItem.objects.fetch_mode(RAISE).get(tag="yellow") msg = "Fetching of TaggedItem.content_object blocked." with self.assertRaisesMessage(FieldFetchBlocked, msg) as cm: @@ -821,6 +820,37 @@ class GenericRelationsTests(TestCase): self.assertIsNone(cm.exception.__cause__) self.assertTrue(cm.exception.__suppress_context__) + def test_fetch_mode_copied_forward_fetching_one(self): + tag = TaggedItem.objects.fetch_mode(FETCH_PEERS).get(tag="yellow") + self.assertEqual(tag.content_object, self.lion) + self.assertEqual( + tag.content_object._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_forward_fetching_many(self): + tags = list(TaggedItem.objects.fetch_mode(FETCH_PEERS).order_by("tag")) + tag = [t for t in tags if t.tag == "yellow"][0] + self.assertEqual(tag.content_object, self.lion) + self.assertEqual( + tag.content_object._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_one(self): + animal = Animal.objects.fetch_mode(FETCH_PEERS).get(pk=self.lion.pk) + self.assertEqual(animal._state.fetch_mode, FETCH_PEERS) + tag = animal.tags.get(tag="yellow") + self.assertEqual(tag._state.fetch_mode, FETCH_PEERS) + + def test_fetch_mode_copied_reverse_fetching_many(self): + animals = list(Animal.objects.fetch_mode(FETCH_PEERS)) + animal = animals[0] + self.assertEqual(animal._state.fetch_mode, FETCH_PEERS) + tags = list(animal.tags.all()) + tag = tags[0] + self.assertEqual(tag._state.fetch_mode, FETCH_PEERS) + class ProxyRelatedModelTest(TestCase): def test_default_behavior(self): diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py index 34b7ffc67d..30fbde873e 100644 --- a/tests/many_to_many/tests.py +++ b/tests/many_to_many/tests.py @@ -1,6 +1,7 @@ from unittest import mock from django.db import connection, transaction +from django.db.models import FETCH_PEERS from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature from .models import ( @@ -589,6 +590,46 @@ class ManyToManyTests(TestCase): querysets=[Publication.objects.all(), Publication.objects.all()], ) + def test_fetch_mode_copied_forward_fetching_one(self): + a = Article.objects.fetch_mode(FETCH_PEERS).get(pk=self.a1.pk) + self.assertEqual(a._state.fetch_mode, FETCH_PEERS) + p = a.publications.earliest("pk") + self.assertEqual( + p._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_forward_fetching_many(self): + articles = list(Article.objects.fetch_mode(FETCH_PEERS)) + a = articles[0] + self.assertEqual(a._state.fetch_mode, FETCH_PEERS) + publications = list(a.publications.all()) + p = publications[0] + self.assertEqual( + p._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_one(self): + p1 = Publication.objects.fetch_mode(FETCH_PEERS).get(pk=self.p1.pk) + self.assertEqual(p1._state.fetch_mode, FETCH_PEERS) + a = p1.article_set.earliest("pk") + self.assertEqual( + a._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_many(self): + publications = list(Publication.objects.fetch_mode(FETCH_PEERS)) + p = publications[0] + self.assertEqual(p._state.fetch_mode, FETCH_PEERS) + articles = list(p.article_set.all()) + a = articles[0] + self.assertEqual( + a._state.fetch_mode, + FETCH_PEERS, + ) + class ManyToManyQueryTests(TestCase): """ diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py index c5fa458570..4d2343e304 100644 --- a/tests/many_to_one/tests.py +++ b/tests/many_to_one/tests.py @@ -941,3 +941,52 @@ class ManyToOneTests(TestCase): a.reporter self.assertIsNone(cm.exception.__cause__) self.assertTrue(cm.exception.__suppress_context__) + + def test_fetch_mode_copied_forward_fetching_one(self): + a1 = Article.objects.fetch_mode(FETCH_PEERS).get() + self.assertEqual(a1._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + a1.reporter._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_forward_fetching_many(self): + Article.objects.create( + headline="This is another test", + pub_date=datetime.date(2005, 7, 27), + reporter=self.r2, + ) + a1, a2 = Article.objects.fetch_mode(FETCH_PEERS) + self.assertEqual(a1._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + a1.reporter._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_one(self): + r1 = Reporter.objects.fetch_mode(FETCH_PEERS).get(pk=self.r.pk) + self.assertEqual(r1._state.fetch_mode, FETCH_PEERS) + article = r1.article_set.get() + self.assertEqual( + article._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_many(self): + Article.objects.create( + headline="This is another test", + pub_date=datetime.date(2005, 7, 27), + reporter=self.r2, + ) + r1, r2 = Reporter.objects.fetch_mode(FETCH_PEERS) + self.assertEqual(r1._state.fetch_mode, FETCH_PEERS) + a1 = r1.article_set.get() + self.assertEqual( + a1._state.fetch_mode, + FETCH_PEERS, + ) + a2 = r2.article_set.get() + self.assertEqual( + a2._state.fetch_mode, + FETCH_PEERS, + ) diff --git a/tests/model_inheritance_regress/tests.py b/tests/model_inheritance_regress/tests.py index 3310497de1..adc2a22fc4 100644 --- a/tests/model_inheritance_regress/tests.py +++ b/tests/model_inheritance_regress/tests.py @@ -7,6 +7,7 @@ from operator import attrgetter from unittest import expectedFailure from django import forms +from django.db.models import FETCH_PEERS from django.test import TestCase from .models import ( @@ -600,6 +601,22 @@ class ModelInheritanceTest(TestCase): self.assertEqual(restaurant.place_ptr.restaurant, restaurant) self.assertEqual(restaurant.italianrestaurant, italian_restaurant) + def test_parent_access_copies_fetch_mode(self): + italian_restaurant = ItalianRestaurant.objects.create( + name="Mom's Spaghetti", + address="2131 Woodward Ave", + serves_hot_dogs=False, + serves_pizza=False, + serves_gnocchi=True, + ) + + # No queries are made when accessing the parent objects. + italian_restaurant = ItalianRestaurant.objects.fetch_mode(FETCH_PEERS).get( + pk=italian_restaurant.pk + ) + restaurant = italian_restaurant.restaurant_ptr + self.assertEqual(restaurant._state.fetch_mode, FETCH_PEERS) + def test_id_field_update_on_ancestor_change(self): place1 = Place.objects.create(name="House of Pasta", address="944 Fullerton") place2 = Place.objects.create(name="House of Pizza", address="954 Fullerton") diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py index da7bd992c0..39f24d6b10 100644 --- a/tests/one_to_one/tests.py +++ b/tests/one_to_one/tests.py @@ -657,3 +657,41 @@ class OneToOneTests(TestCase): p.restaurant self.assertIsNone(cm.exception.__cause__) self.assertTrue(cm.exception.__suppress_context__) + + def test_fetch_mode_copied_forward_fetching_one(self): + r1 = Restaurant.objects.fetch_mode(FETCH_PEERS).get(pk=self.r1.pk) + self.assertEqual(r1._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + r1.place._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_forward_fetching_many(self): + Restaurant.objects.create( + place=self.p2, serves_hot_dogs=True, serves_pizza=False + ) + r1, r2 = Restaurant.objects.fetch_mode(FETCH_PEERS) + self.assertEqual(r1._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + r1.place._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_one(self): + p1 = Place.objects.fetch_mode(FETCH_PEERS).get(pk=self.p1.pk) + self.assertEqual(p1._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + p1.restaurant._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_reverse_fetching_many(self): + Restaurant.objects.create( + place=self.p2, serves_hot_dogs=True, serves_pizza=False + ) + p1, p2 = Place.objects.fetch_mode(FETCH_PEERS) + self.assertEqual(p1._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + p1.restaurant._state.fetch_mode, + FETCH_PEERS, + ) diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py index 6e4acdddf6..bb6417b8ae 100644 --- a/tests/prefetch_related/tests.py +++ b/tests/prefetch_related/tests.py @@ -3,7 +3,13 @@ from unittest import mock from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.db import NotSupportedError, connection -from django.db.models import F, Prefetch, QuerySet, prefetch_related_objects +from django.db.models import ( + FETCH_PEERS, + F, + Prefetch, + QuerySet, + prefetch_related_objects, +) from django.db.models.fetch_modes import RAISE from django.db.models.query import get_prefetcher from django.db.models.sql import Query @@ -108,6 +114,28 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): normal_books = [a.first_book for a in Author.objects.all()] self.assertEqual(books, normal_books) + def test_fetch_mode_copied_fetching_one(self): + author = ( + Author.objects.fetch_mode(FETCH_PEERS) + .prefetch_related("first_book") + .get(pk=self.author1.pk) + ) + self.assertEqual(author._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + author.first_book._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_fetching_many(self): + authors = list( + Author.objects.fetch_mode(FETCH_PEERS).prefetch_related("first_book") + ) + self.assertEqual(authors[0]._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + authors[0].first_book._state.fetch_mode, + FETCH_PEERS, + ) + def test_fetch_mode_raise(self): authors = list(Author.objects.fetch_mode(RAISE).prefetch_related("first_book")) authors[0].first_book # No exception, already loaded diff --git a/tests/select_related/tests.py b/tests/select_related/tests.py index 68fe7a906f..41ed350cf3 100644 --- a/tests/select_related/tests.py +++ b/tests/select_related/tests.py @@ -1,4 +1,5 @@ from django.core.exceptions import FieldError +from django.db.models import FETCH_PEERS from django.test import SimpleTestCase, TestCase from .models import ( @@ -210,6 +211,37 @@ class SelectRelatedTests(TestCase): with self.assertRaisesMessage(TypeError, message): list(Species.objects.values_list("name").select_related("genus")) + def test_fetch_mode_copied_fetching_one(self): + fly = ( + Species.objects.fetch_mode(FETCH_PEERS) + .select_related("genus__family") + .get(name="melanogaster") + ) + self.assertEqual(fly._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + fly.genus._state.fetch_mode, + FETCH_PEERS, + ) + self.assertEqual( + fly.genus.family._state.fetch_mode, + FETCH_PEERS, + ) + + def test_fetch_mode_copied_fetching_many(self): + specieses = list( + Species.objects.fetch_mode(FETCH_PEERS).select_related("genus__family") + ) + species = specieses[0] + self.assertEqual(species._state.fetch_mode, FETCH_PEERS) + self.assertEqual( + species.genus._state.fetch_mode, + FETCH_PEERS, + ) + self.assertEqual( + species.genus.family._state.fetch_mode, + FETCH_PEERS, + ) + class SelectRelatedValidationTests(SimpleTestCase): """ |
