2011-02-02 3 views
2

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

@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 

EDIT: Так Я попытался создать собственный пользовательский менеджер:

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, но o потому что я возвращаю список, я не могу связать эти звонки вместе. Мне нужен способ, чтобы иметь возможность передавать произвольное количество параметров.

ответ

5

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

Это часть менеджера, связанного с вашим классом модели. Экземпляр менеджера по умолчанию имеет имя 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 metaprogramming для моего вкуса.

Я бы предположил, что менеджер не является «общим», но имеет методы в менеджере, которые, в частности, соответствуют базовой модели. Вы не будете называть их 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-стиль. Но это довольно просто и прекрасно работает.

+0

Это похоже на место, где я, вероятно, захочу поставить фильтр. Как бы я начал писать фактический фильтр? Я хочу, чтобы фильтр мог вызвать любой метод или комбинацию методов. – JPC

+1

Возможно ли, чтобы что-то вернуло запрос? Если бы я мог объединить свои фильтры вместе. – JPC

+0

@JPC: «Что-то вернуть QuerySet?» Не легко. «потому что он делает это на основе БД». Не нужно. Вы можете легко добавить свои фильтры за пределы 'filter(). Filter()' свободного API-стиля QuerySet. –

Смежные вопросы