[Django] #37267: Prefetch can populate a reverse foreign key cache with instances of an unrelated queryset model

2 views
Skip to first unread message

Django

unread,
Aug 9, 2026, 7:35:21 PM (13 hours ago) Aug 9
to django-...@googlegroups.com
#37267: Prefetch can populate a reverse foreign key cache with instances of an
unrelated queryset model
-------------------------------------+-------------------------------------
Reporter: beingfaisal | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: dev | Severity: Normal
Keywords: Prefetch | Triage Stage:
prefetch_related queryset model | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
`Prefetch()` accepts a custom queryset whose model is unrelated to the
model represented by a reverse foreign key lookup. If both models contain
a foreign key with the same name, Django can populate the relationship
cache with instances of the wrong model.

For example:

{{{#!python
class Patient(models.Model):
pass


class ChatAlert(models.Model):
patient = models.ForeignKey(
Patient,
related_name="chatalerts",
on_delete=models.CASCADE,
)


class HealthAlert(models.Model):
patient = models.ForeignKey(
Patient,
related_name="healthalerts",
on_delete=models.CASCADE,
)
}}}

The following prefetch is accepted:

{{{#!python
patient = Patient.objects.create()
health_alert = HealthAlert.objects.create(patient=patient)

patient = Patient.objects.prefetch_related(
Prefetch(
"chatalerts",
queryset=HealthAlert.objects.all(),
)
).get(pk=patient.pk)

alerts = list(patient.chatalerts.all())
}}}

`Patient.chatalerts` represents the reverse side of
`ChatAlert.patient`, so it should only contain `ChatAlert` instances.
Instead, `alerts` contains the `HealthAlert` instance.

Both models expose `patient` and `patient_id`, so the reverse foreign key
prefetch machinery can filter and group the incompatible queryset without
raising an error. With a different schema, the same invalid configuration
may instead fail later with a less clear field or attribute error.

I expect evaluating the prefetch to raise `ValueError` when the custom
queryset model is incompatible with the relationship model.

A regression test using existing `prefetch_related` test models fails
with:

{{{
AssertionError: ValueError not raised
}}}

Custom querysets using subclasses of the expected relationship model must
remain supported, as established by #36432. Therefore, compatibility
should
be directional: the supplied queryset model may be the expected model or
one of its subclasses, but not an unrelated model.

AI assistance: OpenAI Codex (GPT-5) helped analyze and draft this report.
I manually verified the reproduction.
--
Ticket URL: <https://code.djangoproject.com/ticket/37267>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Aug 9, 2026, 7:49:36 PM (12 hours ago) Aug 9
to django-...@googlegroups.com
#37267: Prefetch can populate a reverse foreign key cache with instances of an
unrelated queryset model
-------------------------------------+-------------------------------------
Reporter: beingfaisal | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Prefetch | Triage Stage:
prefetch_related queryset model | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by beingfaisal):

For completeness, the issue can be reproduced using models already present
in Django's test suite. The following test can be added to
`PrefetchRelatedTests` in `tests/prefetch_related/tests.py`:

{{{#!python
def test_foreignkey_reverse_incompatible_queryset_model(self):
FavoriteAuthors.objects.create(
author=self.author1,
likes_author=self.author2,
)
queryset = Author.objects.prefetch_related(
Prefetch(
"addresses",
queryset=FavoriteAuthors.objects.all(),
)
)

with self.assertRaises(ValueError):
list(queryset)
}}}

`Author.addresses` represents the reverse side of
`AuthorAddress.author`, so it expects `AuthorAddress` instances. The
custom queryset instead returns unrelated `FavoriteAuthors` instances.

Both models expose `author` and `author_id`, so current `main` evaluates
the prefetch without raising an exception. The test therefore fails with:

{{{
AssertionError: ValueError not raised
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/37267#comment:1>
Reply all
Reply to author
Forward
0 new messages