Единый пользовательский менеджер для нескольких моделей в Django

У меня есть несколько моделей, связанных друг с другом отношениями ForeignKeys.
Основная модель в такой иерархии содержит поле owner.

Я хотел бы создать один пользовательский менеджер для всех этих моделей, который изменяет возвращаемый набор запросов в зависимости от вызывающих его моделей.

Я знаю, что менеджер может получить доступ к self.model, чтобы получить модель, к которой он привязан.

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()

Я хотел бы, чтобы мой Custom Manager имел такое поведение:

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

Чтобы иметь согласованный способ вызова его для разных моделей, например:

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

ВОПРОС:

  • self.model == 'Main' неправильно. Я не понимаю название модели, как это. Есть ли способ получить его?
  • Это эффективно? Знаете ли вы лучший способ реализовать это? Может быть, наследование пользовательских менеджеров?

РЕДАКТИРОВАТЬ - МОЕ РЕШЕНИЕ: Принятый ниже ответ является хорошим решением, но я также нашел способ получить название модели конкретной модели, вызывающей пользовательский менеджер, то есть:

if self.model.__name__ == 'Main':

Ключевым здесь является атрибут __name__


person Leonardo    schedule 31.07.2013    source источник


Ответы (1)


1) Сделать абстрактную модель

class AbstractModel(models.Model):
    class Meta(models.Meta):
        abstract = True

    objects = OwnedManager()

2) Наследуйте свои модели от AbstractModel, поместите ключ в мета

class Model(AbstractModel)
    class Meta(AbstractModel.Meta):
        filter_key = 'some_key'

3) Переделайте свой 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})

Теперь вы можете использовать SomeModel.objects.get_owned_objs(owner=user1) в любых унаследованных моделях, где установлено filter_key без получения имени модели.

person Andrey Nelubin    schedule 31.07.2013
comment
Спасибо, это выглядит хорошим решением, я попробую. Я также нашел способ получить название модели из пользовательского менеджера. Я обновил свой вопрос, включая также мое решение. - person Leonardo; 02.08.2013