问题
I have several models connected to each other with ForeignKeys relationships.
The main one in this sort of hierarchy contains a owner field.
I would like to create a single custom manager for all these models that changes the returned queryset depending on the models that is calling it.
I know that manager can access self.model
to get the model that it is attached to.
Class Main(models.Model)
owner=models.ForeignKey (User)
owned = OwnedManager()
Class Second(models.Model)
main=models.ForeignKey('Main')
owned = OwnedManager()
Class Third(models.Model)
second=models.ForeignKey('Second')
owned = OwnedManager()
I would like my Custom Manager to have this sort of behavior:
class OwnedManager(models.Manager):
def get_owned_objs(self, owner):
if self.model == 'Main': # WRONG: How do I get the model name?
owned_main = self.filter(owner=owner)
return owned_main
elif self.model == 'Second':
owned_second = self.filter(main__owner=owner)
return owned_second
else:
owned_third = self.filter(second__main__owner=owner)
return owned_third
In order to have a consistent way to call it across different models, like so:
main_object.owned.get_owned_objs(owner=user1) # of the Model Main
second_object.owned.get_owned_objs(owner=user1) # of the Model Second
third_object.owned.get_owned_objs(owner=user1) # of the Model Third
QUESTION:
self.model == 'Main'
is wrong. I don't get the model name like this. Is there a way to get it?- Is this efficient? Do you know a better way to implement this? Maybe Custom Managers Inheritance?
EDIT - MY SOLUTION: The accepted answer below is a good solution but I also found a way to get the model name of the particular model calling the custom manager, that is:
if self.model.__name__ == 'Main':
The key here is the attribute __name__
回答1:
1) Make abstract model
class AbstractModel(models.Model):
class Meta(models.Meta):
abstract = True
objects = OwnedManager()
2) Inherit your models from AbstractModel, put some key in meta
class Model(AbstractModel)
class Meta(AbstractModel.Meta):
filter_key = 'some_key'
3) Redesign your OwnedManager
class OwnedManager(models.Manager):
def get_owned_objs(self, owner):
if hasattr(self.model._meta, 'filter_key'):
return self.filter(**{self.model._meta.filter_key: owner})
Now you can use SomeModel.objects.get_owned_objs(owner=user1)
in any inherited models, where filter_key
is setted without getting models's name.
来源:https://stackoverflow.com/questions/17968501/single-custom-manager-for-multiple-models-in-django