Django - пользовательский фильтр, вызывающий метод - PullRequest
2 голосов
/ 03 февраля 2011

Я знаю, что вы не можете вызвать метод, используя фильтр, потому что он делает это на основе БД. Поэтому я пытаюсь написать собственный фильтр.

    @staticmethod
    def custom_filter(obj,method_name, arg=False):
        for i in obj.objects.all():
            if getattr(i, method_name)() == arg:
                yield i

Я могу заставить это работать, если позвоню:

MyModel.custom_filter(MyModel,'my_method','myarg')

однако я не могу связать их вместе, как обычные фильтры.

Я мог бы сделать что-то вроде этого:

@staticmethod
def custom_double_filter(obj,method1,arg1,method2,arg2):
    for i in obj.objects.all():
        if getattr(i, method1)() == arg1 and getattr(i,method2)()==arg2:
            yield i

но я бы хотел, чтобы он поддерживал произвольное количество фильтров И некоторые методы имеют свои собственные аргументы

@staticmethod
def custom_double_filter(obj,method1,arg1,method2,arg2):
    for i in obj.objects.all():
        if getattr(i, method1)(<may need to pass an argument>) == arg1 and getattr(i,method2)()==arg2:
            yield i

РЕДАКТИРОВАТЬ: Итак, я попытался сделать пользовательский менеджер, например, так:

class GroupManager(models.Manager):
    use_for_related_fields = True

    def custom_filter(self,method_name, arg=False):
        results = []
        for i in self.all():
            if getattr(i, method_name)() == arg:
                results.append(i)
        return results

Это работает для одного вызова custom_filter, но, очевидно, поскольку я возвращаю список, я не могу связать эти вызовы вместе. Мне нужен способ, чтобы иметь возможность передавать произвольные числа параметров

1 Ответ

5 голосов
/ 03 февраля 2011

Фильтры не являются частью вашего модельного класса.

Они являются частью менеджера, связанного с вашим классом модели. Экземпляр менеджера по умолчанию называется objects.

Однако вы можете добавить менеджеров с необычными фильтрами.

http://docs.djangoproject.com/en/1.2/topics/db/managers/

Когда вы пишете свой собственный, настроенный менеджер, обязательно прочитайте этот раздел: http://docs.djangoproject.com/en/1.2/topics/db/managers/#controlling-automatic-manager-types, чтобы ваш новый менеджер делал все, что делал менеджер по умолчанию, а также ваш новый необычный фильтр.

Я хочу, чтобы фильтр мог вызывать любой метод или комбинацию методов

Это немного безумно, но вы могли бы заставить это работать. Вызов «любого метода» означает, что вы должны подготовить и передать все необходимые аргументы этой функции метода. На мой вкус, он начинает слишком много метапрограммировать *arg и **kw.

Я бы предположил, что менеджер не является «общим», но имеет методы в менеджере, которые, в частности, соответствуют базовой модели. Ты не будешь называть их filter. вы просто сопоставите их с моделью.

Я думаю, что простые методы менеджера, которые отображаются на простые методы модели, - это лучшее, что вы собираетесь сделать.

Кроме того, у вас есть старые добрые понимания списков Python и функции генератора. Мы используем это.

def our_special_filter( some_queryset ):
    for row in some_queryset:
        if row.aMethod(): yield row

result= our_special_filter( SomeModel.objects.filter(...) )

Да. Это нарушает хороший свободный стиль API. Но это довольно просто и прекрасно работает.

...