Opened 15 months ago
Last modified 15 months ago
#34791 closed Bug
Issue when using Prefetch objects in prefetch_related — at Initial Version
Reported by: | Maxime Toussaint | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 4.2 |
Severity: | Normal | Keywords: | prefetch, prefetch_related |
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
There seems to be an issue when using a Prefetch object to fetch something that has already been fetched. Here is an example: so let's say I have a Pizza and some Toppings. Now I want to get all the toppings, but for some reason I also want to separately fetch only the toppings that are out of stock. I could do something like:
queryset = Pizza.objects.all().prefetch_related( 'toppings', Prefetch('toppings', queryset=Topping.objects.filter(is_in_stock=False), to_attr='out_of_stock_toppings'), )
This looks good, but if we run it, it will fail, saying out_of_stock_toppings is not an attribute of Pizza. However, if I were to do it like this instead:
queryset = Pizza.objects.all().prefetch_related( Prefetch('toppings', queryset=Topping.objects.filter(is_in_stock=False), to_attr='out_of_stock_toppings'), 'toppings', )
then all works fine. Looking at the code, this seems to be because the name used by a field to validate the cache is not the name used to store the data on the model, but rather simply the name of the field, so it collides. I have not tested it, but I think in the second example, the data returned will actually be the filtered data, not the full expected queryset. Note that this is my first time reading that part of the code, so there could be things I missed.
Now this is a bit of a nonsensical example, but when using rest_framework with serializers, this type of situation could come up, where one serializer needs it formatted a certain way and this issue could arise (it has for me).
I am not sure what the best way to fix this would be, but I feel like setting a to_attr should make the cache take that new field name into account instead of the field name.