prefetch_related_objects evaluates queryset when checking for invalid prefetch ordering.
When encountering a prefetch it has already seen and checking whether to throw the "lookup was already seen with a different queryset" ValueError, prefetch_related_objects will inadvertently evaluate lookup.queryset. For example:
foo = Foo.objects.create()
prefetches = [
'bar',
Prefetch('bar', queryset=Bar.objects.filter(my_field=True))
]
prefetch_related_objects([foo], *prefetches)
Right before it throws the ValueError, the above code will execute the full unfiltered query Bar.objects.filter(my_field=True)
. This may match a very large number of rows (or a whole table), since it is not restricted to Bars
related to the specific foo
. In our case this led to the query timing out and the page returning a 504 without the code ever actually reaching the ValueError.
Change History
(6)
Owner: |
set to Iain P. Watts
|
Type: |
Uncategorized → Bug
|
Summary: |
prefetch_related_objects evaluates lookup.queryset when checking for invalid prefetch ordering → prefetch_related_objects evaluates queryset when checking for invalid prefetch ordering.
|
Triage Stage: |
Unreviewed → Accepted
|
Version: |
2.2 → master
|
Resolution: |
→ fixed
|
Status: |
assigned → closed
|
https://github.com/django/django/pull/11369