Использование функции пользовательского менеджера Django в уже отфильтрованном наборе запросов - PullRequest
2 голосов
/ 28 апреля 2011

Рассмотрим следующий случай:

class MyModelManager(models.Manager):
    def my_filter(self):
     return [some code here].filter(field_A__gt=3)

class MyModel(models.Model):
    # some fields
    objects = MyModelManager()


# The way I'd like to use it:
qs = MyModel.objects.filter(field_B__lt=1)
# some code
qs = qs.my_filter()

Обратите внимание, что я хотел бы использовать пользовательскую функцию my_filter() в уже отфильтрованном наборе запросов.Какой код я должен поместить в [some code here] выше?Является ли структура в целом правильной?

Ответы [ 3 ]

2 голосов
/ 28 апреля 2011

Я думаю, что нет способа сделать это именно так. MyModel.objects.filter (field_B__lt = 1) вернет объект QuerySet, а не MyModelManager. Вы можете либо передать его методу my_filter, как упомянул Игнасио Васкес-Абрамс, либо сначала применить my_filter к своему менеджеру, который вернет объект QuerySet, который вы можете отфильтровать далее

1 голос
/ 28 апреля 2011

Ваш подход неверен, поскольку вы можете использовать Model.Manager только при извлечении данных из базы данных, поэтому использование двух менеджеров или попытка использовать менеджера в наборе запросов приводит к ошибке.

data = SomeModel.objects.my_manager.all()

или

data = SomeModel.objects.all()
data = data.my_manager.filter(...)

неправильно, так как вы не можете использовать два менеджера ...

Одним из возможных waw является определение функции, которая получает набор запросов в качестве параметра и возвращает отфильтрованный набор запросов ...

def extra_filter(queryset):
    queryset = queryset.filter(...)

но я не уверен, поможет ли это.

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

class SomeManager(models.Manager):
    def get_query_set(self):
        return super(SomeManager, self).get_query_set().filter(<filteer criteria>)

class MyModel(models.Model):
    # some fields
    objects = models.Manager()
    mymanager = SomeManager()

data = MyModel.mymanager.all() 

И использовать только один ...

ОБНОВЛЕНИЕ: в django наборы запросов ленивы. Это означает, что вы можете применять столько фильтров, сколько пожелаете, и данные не будут извлечены из базы данных, если только вы не попытаетесь получить конкретную запись из отфильтрованной или попытаетесь нарезать ее ... Документация здесь

Итак, нет разницы между

qs = MyModel.objects.filter(field_B__lt=1)
qs = qs.filter(field_A__gt=3)

и

qs = MyModel.objects.filter(field_A__gt=3)
qs = qs.filter(field_B__lt=1)

Таким образом, определение менеджера для применения специфической фильтрации является основной причиной использования менеджеров ...

Вы определяете своего менеджера:

class SomeManager(models.Manager):
    def get_query_set(self):
        return super(SomeManager, self).get_query_set().filter(field_A__gt=3)

тогда вы вызываете его с другими критериями фильтрации:

Somemodel.mymodelmanager.filter(field_B__lt=1, ....)

И django добавит все фильтры и изменит запрос, когда вы этого хотите.

Так что, если вы часто используете этот фильтр, то менеджер - лучший выбор ...

Как в примере, у меня есть поле valid _ в большинстве моих моделей баз данных и менеджер val , который фильтрует недопустимые записи. Поэтому, когда я хочу отфильтровать все действительные данные (90% времени), я использую

Somemodel.val.filter(...)

И в ситуации, когда мне нужны все данные, я просто использую базовый менеджер django:

Somemodel.objects.filter(...)
0 голосов
/ 28 апреля 2011
class MyModelManager(models.Manager):
    def my_filter(self, qs=None):
        if qs is None:
            qs = [however you got it before]
        return qs.filter(field_A__gt=3)

Затем просто передайте ему свой набор запросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...