Opened 5 months ago
Closed 5 months ago
#36442 closed Bug (fixed)
Reusing same instance of FilteredRelations in multiple queries result in django.core.exceptions.FieldError: Cannot resolve keyword
| Reported by: | Viliam Mihálik | Owned by: | Viliam Mihálik |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 5.0 |
| Severity: | Normal | Keywords: | FilteredRelation, ORM |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Example test case that should pass, used in FilteredRelationTests
def test_reuse_same_filtered_relation(self):
borrower = Borrower.objects.create(name="Jenny")
Reservation.objects.create(
borrower=borrower,
book=self.book1,
state=Reservation.STOPPED,
)
condition = Q(book__reservation__state=Reservation.STOPPED)
my_reserved_books = FilteredRelation(
"book__reservation",
condition=condition
)
first_result = list(Author.objects.annotate(
my_reserved_books=my_reserved_books,
))
self.assertEqual(my_reserved_books.condition, condition)
# AssertionError: <Q: (AND: ('my_reserved_books__state', 'stopped'))> != <Q: (AND: ('book__reservation__state', 'stopped'))>
second_result = list(Author.objects.annotate(
my_reserved_books=my_reserved_books,
))
# django.core.exceptions.FieldError: Cannot resolve keyword 'my_reserved_books' into field. Choices are: book, content_object, content_type, content_type_id, favorite_books, id, name, object_id
When you reuse same FilteredRelation in different queries, internal FilteredRelation.condition is changed and no longer works.
This same code works on Django 4.x. This change was introduced by fixing of bug #33766
Based on discussion in #33766 it was intended but breaking for us after upgrading from 4 -> 5.
In order to get this working is to my_reserved_books.clone() clone annotate before using.
Change History (6)
comment:1 by , 5 months ago
| Triage Stage: | Unreviewed → Accepted |
|---|---|
| Type: | Uncategorized → Bug |
| Version: | 5.2 → 5.0 |
comment:2 by , 5 months ago
I can look at it.
I checked the code, and after debug, .clone method is never called. So my suggestion is to clone annotation before "rename" here
https://github.com/django/django/blob/main/django/db/models/query.py#L1728
and simply change clone.query.add_filtered_relation(annotation, alias) to clone.query.add_filtered_relation(annotation.clone(), alias)
comment:3 by , 5 months ago
| Has patch: | set |
|---|
comment:4 by , 5 months ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:5 by , 5 months ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
We should definitely clone the filtered relation on resolving, the bug is present since 5.0 though so it doesn't qualify for a backport.
Would you be interested in submitting a patch here? I suspect adjusting
FilteredRelation.cloneto make sure it passescondition=self.condition.clone()should do?