2012-03-12 1 views
18

Есть ли фильтр отрицания по умолчанию. Идея заключается в том, что вы можете сделать следующее в Джанго ОРМ:Отрицательный фильтр Tastypie

model.objects.filter(field!=value) 

Как я могу это сделать в tastypie, если это вообще возможно. Я пробовал:

someapi.com/resource/pk/?field__not=value 
someapi.com/resource/pk/?field__!=value 
someapi.com/resource/pk/?field!=value 

И все они дали мне ошибки.

+1

В некоторых случаях у вас есть возможность заменить его с некоторыми фильтрами, такими как, что: 'field__not = null' можно заменить' field__isnull = false', «_not больше than_» можно заменить? просто '? field__lte = x' (так с" _less than equal_ "). Также учтите, что Django может каким-то образом позволить вам передать значение 'field! = Value' в качестве аргумента, но это приведет к тому, что далее будет добавлено логическое значение (или' NameError', если 'field' не является определенной переменной). Или я ошибаюсь, и Django выполняет перегрузку оператора, например. web2py делает в случае построителя запросов? – Tadeck

ответ

27

К сожалению, нет.

Проблема заключается в том, что класс ModelResource Tastypie использует только метод filter() для QuerySet, т. Е. Он не использует exclude(), который должен использоваться для отрицательных фильтров. Нет никакого поиска фильтра(), который будет означать отрицание. Допустимыми являются поиски (после этого SO post):

exact 
iexact 
contains 
icontains 
in 
gt 
gte 
lt 
lte 
startswith 
istartswith 
endswith 
iendswith 
range 
year 
month 
day 
week_day 
isnull 
search 
regex 
iregex 

Однако это не должно быть так трудно реализовать поддержку что-то вроде «__not_eq». Все, что вам нужно сделать, это изменить метод apply_filters() и отделить фильтры с помощью «__not_eq» от остальных. Затем вы должны передать первую группу, чтобы исключить(), а остальную часть - в filter().

Что-то вроде:

def apply_filters(self, request, applicable_filters): 
    """ 
    An ORM-specific implementation of ``apply_filters``. 

    The default simply applies the ``applicable_filters`` as ``**kwargs``, 
    but should make it possible to do more advanced things. 
    """ 
    positive_filters = {} 
    negative_filters = {} 
    for lookup in applicable_filters.keys(): 
     if lookup.endswith('__not_eq'): 
      negative_filters[ lookup ] = applicable_filters[ lookup ] 
     else: 
      positive_filters[ lookup ] = applicable_filters[ lookup ] 

    return self.get_object_list(request).filter(**positive_filters).exclude(**negative_filters) 

вместо значения по умолчанию:

def apply_filters(self, request, applicable_filters): 
    """ 
    An ORM-specific implementation of ``apply_filters``. 

    The default simply applies the ``applicable_filters`` as ``**kwargs``, 
    but should make it possible to do more advanced things. 
    """ 
    return self.get_object_list(request).filter(**applicable_filters) 

должен предусматривать следующий синтаксис:

someapi.com/resource/pk/?field__not_eq=value 

я не проверял. Это, вероятно, может быть записано в более изящным способом тоже, но должны получить вы собираетесь :)

+0

Ключ к фильтру в negative_filters не должен быть «field__not_eq», но «field__exact», поэтому модули Django ORM могут справиться с этим. Кроме того, build_filters должны быть перезаписаны, поэтому «__not_eq» не рассматривается как отношение Tastypie. – Wilerson

2

Я открыл ошибку для этого и при условии, простое решение здесь: https://github.com/toastdriven/django-tastypie/issues/524

Это, вероятно, будет лучше, чтобы добавить '!' символ в конце имени поля, как вы сделали в вашем вопросе ...

6

Другой способ сделать это без изменения кода является использование iregex с inverse matching

http://HOST/api/v1/resource/?format=json&thing__iregex=^((?!notThis).)*$ 
-1

Я использую исключения(), чтобы избежать некоторых значений. Например:

Person.filter(name="Tim").exclude(state="Down");