Issue
I am in a situation where I need to use a custom manager for a related field which is different from the base_manager for the related fields. Let's say that I have a model Item
which is in one to many relation with another model Purchase
. Now, Item
has 2 managers:
objects = ItemManager() #which by default excludes the out_of_stock=True items
complete = CompleteItemManager() #which gives all the items.
For all the other models related to Item
, ItemManager
is the default one. But in Purchase
, I would want to use the CompleteItemManager
for the related Item.
So let's say there was once a purchase for an item which is now has out_of_stock=True
and we just have the id of that purchase say old_purchase_id
, now if try to run the below query:
purchase = Purchase.objects.filter(id=old_purchase_id) # gives error
It would give an error like "Item matching query does not exist"
as the manager being used for the related items is ItemManager which excludes such out of stock items.
What can be done in that case? Ideally I would want something to override the manager to be used for a given related field per model, so that even if all other models use ItemManager
to resolve item fields, the Purchase
Model still uses the CompleteItemManager
for its relations with Item
.
Solution
Here's how I did it.
I made a CustomForwardManyToOneDescriptor
which would just pick the manager named complete
for the related model. And used that descriptor in a CustomForeignKey
as the forward_related_accessor_class
.
class CustomForwardManyToOneDescriptor(ForwardManyToOneDescriptor):
def get_queryset(self, **hints):
related_model = self.field.remote_field.model
return related_model.complete.db_manager(hints=hints).all()
class CustomForeignKey(models.ForeignKey):
forward_related_accessor_class = CompleteManagerForwardManyToOneDescriptor
Now using the CustomForeignKey
instead of ForeignKey
to create OneToMany relation with a model would make that model use the complete manager for the foreign key field no matter what the default related manager is.
Answered By - Neeraj Kumar
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.