Пользовательский менеджер Django для динамической фильтрации архивированных объектов

#python #django

#python #django

Вопрос:

Предположим, у меня есть модель:

 class Car(models.Model):
    name = models.CharField(max_length=50)
    is_active = models.BooleanField(default=True)
  

Когда я запрашиваю Car, я всегда хочу возвращать объекты, удовлетворяющие is_active=True .
Для этого, выполняя поиск в StackOverflow, я понимаю, что лучше всего использовать ModelManager, например:

 class CarManager(models.ModelManager):
    def get_queryset(self):
        return super().get_queryset().filter(is_active=True)
  

И используйте этот менеджер в моей модели.

 class Car(models.Model):
    name = models.CharField(max_length=50)
    is_active = models.BooleanField(default=True)
    objects = CarManager()
  

Использование этого решения всегда возвращает активный набор запросов Car.
Но иногда я также хочу вернуть неактивный набор запросов Car, и я не хочу писать другой ModelManager.

Для разработки,

  1. Когда я запускаю,

    Car.objects.all() или,

    Car.objects.filter(name__contains=’Car’) или,

    Car.objects.filter(is_active=True)

Мне нужен только активный набор запросов Car.

  1. Когда я запускаю,

    Car.objects.filter(is_active=False)

Я хочу иметь неактивный набор запросов Car.

И я хочу добиться этого, используя единый ModelManager и методы по умолчанию (get, filter, all и т. Д.). Почему я хочу этого, потому что он уже использовался во многих местах.

Итак, есть ли какой-либо способ добиться этого? Любые предложения или идеи сердечно приветствуются.

Заранее спасибо за помощь.

Ответ №1:

Итак, после долгих исследований и изучения документации и исходного кода Django я придумал это для метода filter():

 class CarManager(models.ModelManager):
    def filter(self, *args, **kwargs):
        if kwargs.get('is_active') == False:
            return super().get_queryset().filter(*args, **kwargs)
        return self.get_queryset().filter(*args, **kwargs)
    
    def get_queryset(self):
        return super().get_queryset().filter(is_active=True)
  

Здесь я переопределил метод filter(), чтобы:

  1. Если передается is_active=False, вызывается родительский (по умолчанию) get_queryset(), за которым следует filter().
  2. Если is_active не передается или передается is_active=True, вызывается переопределенный метод get_queryset() (который возвращает активный набор запросов Car), за которым следует метод filter().

Если есть какие-либо другие решения или лучшие практики, пожалуйста, укажите их. Спасибо.

Ответ №2:

Боюсь, это невозможно, поскольку вы перезаписываете базовый набор запросов менеджера. Что вы могли бы сделать вместо создания другого менеджера, так это реализовать дополнительный метод, который возвращает набор запросов только с неактивными машинами, что-то вроде:

 class CarManager(models.ModelManager):
    def get_queryset(self):
        return super().get_queryset().filter(is_active=True)

    def get_inactive_cars(self):
        return super().get_queryset().filter(is_active=False)

  

А затем замените наборы запросов, в которых вы извлекаете неактивные:

 Car.objects.get_inactive_cars()

  

Комментарии:

1. О, разве невозможно использовать параметры запроса? Например, проверить, используется ли is_active в фильтре, и вернуть соответствующий результат?