Opened 10 hours ago
Last modified 6 hours ago
#37027 new Bug
refresh_from_db() with from_queryset + prefetch does not persist result in instance
| Reported by: | Hugo Maingonnat | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 5.2 |
| Severity: | Normal | Keywords: | refresh_from_db, prefetch |
| Cc: | MANAS MADESHIYA | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
foo = Foo.objects.create(**data)
# The prefetch query is executed, but does not seem to be persisted into the instance
prefetch = Prefetch('bar_set', queryset=Bar.objects.all())
foo.refresh_from_db(from_queryset=Foo.objects.prefetch_related(
prefetch
))
# This is empty
print('CACHE:', foo._prefetched_objects_cache)
# Lazy extra query is executed because prefetch was not persisted: this should not happen
list(foo.bar_set.all())
This also does not work if for example to_attr='bar_list' is set in the prefetch, then foo.bar_list is not set.
Note that using select_related() is working.
Note:
See TracTickets
for help on using tickets.
There's is little value in using
prefetch_relatedwhen dealing with a single object as this method is meant to be used to prevent N+1 query issues but in this caseN=1so the number of queries will be the same. In other words, performingfoo.bar_set.all()will issue the same query as what a prefetching would have done.When we added
refresh_from_db(from_queryset)support (#28344) we knew it would open the door to a large surface area betweenModelandQuerySetAPIs. Given the original intent was to supportfor_updateand friends I'm not convinced we should add support forprefetch_relatedand certainly not forPrefetch(to_attr)as it doesn't follow therefresh_from_db(fields)convention.Support for
select_relatedcame for free as it's a normal attribute lookup on the retrieved model instance and there are real benefits to using it (reducing the number of queries). In the case ofprefetch_relatedit requires extra retrieval and invalidation logic of many-to-many relationships and results in the same number of queries. I believe accepting this work would open the door to supporting the fullModelXQuerySetintersection which would include cases likeannotatemembers being ignored as well.