Opened 3 months ago
Closed 3 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 , 3 months ago
Triage Stage: | Unreviewed → Accepted |
---|---|
Type: | Uncategorized → Bug |
Version: | 5.2 → 5.0 |
comment:2 by , 3 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 , 3 months ago
Has patch: | set |
---|
comment:4 by , 3 months ago
Owner: | set to |
---|---|
Status: | new → assigned |
comment:5 by , 3 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.clone
to make sure it passescondition=self.condition.clone()
should do?