From 60a17fccf4f2fa31b823b0f938005897f2f3ef16 Mon Sep 17 00:00:00 2001 From: Yassin Bahri <131185064+yassinbahri@users.noreply.github.com> Date: Wed, 26 Aug 2026 10:34:57 +0200 Subject: [PATCH 1/2] Fixed #37300 -- Preserved parent instance hints on custom Prefetch querysets. Regression in 821619aa8771ef211c4c4922001efdf914201ca3. Thanks Norbert Kwizera for the report. --- .../db/models/fields/related_descriptors.py | 2 ++ docs/releases/6.1.1.txt | 5 +++ tests/prefetch_related/tests.py | 32 +++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py index eafcb63ceb7c..32bc8d56c5c9 100644 --- a/django/db/models/fields/related_descriptors.py +++ b/django/db/models/fields/related_descriptors.py @@ -180,6 +180,7 @@ def get_prefetch_querysets(self, instances, querysets=None): "length of 1." ) queryset = querysets[0] + queryset._add_hints(instance=instances[0]) else: _cloning_disabled = True queryset = self.get_queryset(instance=instances[0])._disable_cloning() @@ -480,6 +481,7 @@ def get_prefetch_querysets(self, instances, querysets=None): "length of 1." ) queryset = querysets[0] + queryset._add_hints(instance=instances[0]) else: _cloning_disabled = True queryset = self.get_queryset(instance=instances[0])._disable_cloning() diff --git a/docs/releases/6.1.1.txt b/docs/releases/6.1.1.txt index cfffb5fe5056..940c815c9b24 100644 --- a/docs/releases/6.1.1.txt +++ b/docs/releases/6.1.1.txt @@ -21,6 +21,11 @@ Bugfixes detect mixed ``on_delete`` variants for auto-created intermediate models for ``ManyToManyField``\s (:ticket:`37254`). +* Fixed a regression in Django 6.1 where custom querysets used with + :class:`~django.db.models.Prefetch` for forward foreign key or reverse + one-to-one relationships were not routed using the parent queryset's + database (:ticket:`37300`). + * Fixed a regression in Django 6.1 where HTML-safe strings, such as those created with :func:`~django.utils.safestring.mark_safe`, used as form media assets were treated as asset paths rather than being rendered verbatim diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py index bda187a92a0a..eac01f8d6c54 100644 --- a/tests/prefetch_related/tests.py +++ b/tests/prefetch_related/tests.py @@ -1747,6 +1747,38 @@ def test_using_is_honored_custom_qs(self): ) self.assertEqual(books, "Poems ()\n" "Sense and Sensibility ()\n") + def test_forward_fk_prefetch_custom_queryset_uses_parent_database(self): + book1 = Book.objects.using("default").create(title="Dive into Python") + Author.objects.using("default").create(name="Mark", first_book=book1) + book2 = Book.objects.using("other").create(title="Dive into Rust") + Author.objects.using("other").create(name="Mark", first_book=book2) + + author = ( + Author.objects.using("other") + .prefetch_related(Prefetch("first_book", queryset=Book.objects.all())) + .get(name="Mark") + ) + + self.assertEqual(author._state.db, "other") + self.assertEqual(author.first_book._state.db, "other") + self.assertEqual(author.first_book.title, "Dive into Rust") + + def test_reverse_o2o_prefetch_custom_queryset_uses_parent_database(self): + BookWithYear.objects.using("default").create(title="Poems", published_year=2000) + BookWithYear.objects.using("other").create(title="Poems", published_year=2001) + + book = ( + Book.objects.using("other") + .prefetch_related( + Prefetch("bookwithyear", queryset=BookWithYear.objects.all()) + ) + .get(title="Poems") + ) + + self.assertEqual(book._state.db, "other") + self.assertEqual(book.bookwithyear._state.db, "other") + self.assertEqual(book.bookwithyear.published_year, 2001) + class Ticket19607Tests(TestCase): @classmethod From 5babd2e21ac0877d66c5452da17b97608b337fba Mon Sep 17 00:00:00 2001 From: Mariano Baragiola Date: Fri, 31 Jul 2026 23:34:30 -0300 Subject: [PATCH 2/2] Fixed #37237 -- Improved RelatedIn lookup preparation performance. Thanks Simon Charette for the implementation idea. --- django/db/models/fields/related_lookups.py | 1 + 1 file changed, 1 insertion(+) diff --git a/django/db/models/fields/related_lookups.py b/django/db/models/fields/related_lookups.py index 639c29d7ba4c..47a411125da7 100644 --- a/django/db/models/fields/related_lookups.py +++ b/django/db/models/fields/related_lookups.py @@ -66,6 +66,7 @@ def get_prep_lookup(self): -1 ] self.rhs = [target_field.get_prep_value(v) for v in self.rhs] + self.prepare_rhs = False elif not getattr(self.rhs, "has_select_fields", True) and not getattr( self.lhs.field.target_field, "primary_key", False ):