summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAdam Johnson <me@adamj.eu>2025-04-14 15:12:28 +0100
committerJacob Walls <jacobtylerwalls@gmail.com>2025-10-16 14:52:22 -0400
commit6dc9b04018032dccbb5ad8347f7ddf4341316166 (patch)
treeda87f218b3992788d5804c552edffd270c030b7a /tests
parent821619aa8771ef211c4c4922001efdf914201ca3 (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.py37
-rw-r--r--tests/generic_relations/tests.py32
-rw-r--r--tests/many_to_many/tests.py41
-rw-r--r--tests/many_to_one/tests.py49
-rw-r--r--tests/model_inheritance_regress/tests.py17
-rw-r--r--tests/one_to_one/tests.py38
-rw-r--r--tests/prefetch_related/tests.py30
-rw-r--r--tests/select_related/tests.py32
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):
"""