Как сделать неравное в фильтрации наборов запросов Django?

442

В Django-модели QuerySets я вижу, что для сравнительных значений есть __gt и __lt, но есть ли __ne/!=/<> ( не равно?)

Я хочу отфильтровать с помощью не равно:

Пример:

Model:
    bool a;
    int x;

Я хочу

results = Model.objects.exclude(a=true, x!=5)

!= - неправильный синтаксис. Я пробовал __ne, <>.

В итоге я использовал:

results = Model.objects.exclude(a=true, x__lt=5).exclude(a=true, x__gt=5)
  • 71
    Сработали бы результаты = Model.objects.exclude (a = true) .filter (x = 5)?
  • 2
    @hughdbrown. Нет. Ваш запрос сначала исключает все a=true а затем применяет фильтр x=5 к остальным. Предполагаемый запрос требует только тех, у которых есть a=true и x!=5 . Разница в том, что все те, у кого a=true и x=5 , также отфильтрованы.
Теги:
django-models
django-queryset

11 ответов

447
Лучший ответ

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

Обновление: я просто попробовал, кажется, работает очень хорошо:

>>> from myapp.models import Entry
>>> from django.db.models import Q

>>> Entry.objects.filter(~Q(id = 3))

[<Entry: Entry object>, <Entry: Entry object>, <Entry: Entry object>, ...]
  • 11
    @ JCLeitão: см. Также ответ @ d4nt ниже для более понятного синтаксиса.
428

В вашем запросе есть двойной отрицательный результат, вы хотите исключить все строки, где x не 5, поэтому, другими словами, вы хотите включить все строки, где x IS 5. Я считаю, что это будет трюк.

results = Model.objects.filter(x=5).exclude(a=true)

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

  • 0
    @ d4nt: я могу ошибаться, но я думаю, что запрос должен быть следующим results = Model.objects.filter(a=true).exclude(x=5)
  • 1
    @Taranjeet: Я думаю, что вы неправильно прочитали исходный запрос. Версия d4nt верна, потому что OP хотел исключить (a = True) и отменить исключение x = 5 (т.е. включить его).
Показать ещё 4 комментария
91

Синтаксис field=value в запросах является сокращением для field__exact=value. То есть Django помещает операторы запросов в поля запроса в идентификаторы. Django поддерживает следующие операторы:

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

Я уверен, объединив их с объектами Q как Dave Vogt предлагает и используя filter() или exclude() как Джейсон Бейкер предлагает, вы получите именно то, что вам нужно для любого возможного запроса.

  • 0
    спасибо, это круто я использовал что-то вроде этого tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$') и это работает.
  • 0
    @suhail, учтите, что не все базы данных поддерживают этот синтаксис регулярных выражений :)
Показать ещё 2 комментария
43

Легко создать пользовательский поиск с помощью Django 1.7. Там __ne пример поиска в официальной документации Django.

Сначала нужно создать поиск:

from django.db.models import Lookup

class NotEqual(Lookup):
    lookup_name = 'ne'

    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = lhs_params + rhs_params
        return '%s <> %s' % (lhs, rhs), params

Затем вам необходимо зарегистрировать его:

from django.db.models.fields import Field
Field.register_lookup(NotEqual)

И теперь вы можете использовать поиск __ne в ваших запросах следующим образом:

results = Model.objects.exclude(a=True, x__ne=5)
  • 2
    Отличный ответ и буквально единственный, который на самом деле отвечает на вопрос.
  • 0
    Черт возьми, это на самом деле работает, и даже в URL админа. Отличный ответ, спасибо.
39

В Django 1.9/1.10 есть три варианта.

  • Цепочка exclude и filter

    results = Model.objects.exclude(a=true).filter(x=5)
    
  • Используйте Q() объекты и ~ оператор

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
    
  • Зарегистрируйте пользовательскую функцию поиска

    from django.db.models import Lookup
    from django.db.models.fields import Field
    
    @Field.register_lookup
    class NotEqual(Lookup):
        lookup_name = 'ne'
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s <> %s' % (lhs, rhs), params
    

    Декоратор register_lookup был добавлен в Django 1.8 и позволяет выполнять обычную проверку, как обычно:

    results = Model.objects.exclude(a=True, x__ne=5)
    
  • 1
    object_list = QuerySet.filter (~ Q (a = True), x = 5): не забудьте сохранить все остальные условия, не содержащие Q, после тех, которые содержат Q.
  • 0
    @BhumiSinghal Почему?
Показать ещё 1 комментарий
37

В то время как с помощью моделей вы можете фильтровать с помощью =, __gt, __gte, __lt, __lte, вы не можете использовать ne, != или <>. Тем не менее, вы можете добиться лучшей фильтрации при использовании объекта Q.

Вы можете избежать цепочки QuerySet.filter() и QuerySet.exlude() и использовать это:

from django.db.models import Q
object_list = QuerySet.filter(~Q(field='not wanted'), field='wanted')
10

Вы должны использовать filter и exclude как это

results = Model.objects.exclude(a=true).filter(x=5)
8

Ожидаемое дизайнерское решение. Между тем, используйте exclude()

Отслеживание проблем Django имеет замечательную запись # 5763, под названием "Queryset не имеет" не равного "оператора фильтра". Это замечательно, потому что (по состоянию на апрель 2016 года) это было "открылся 9 лет назад" (в эпоху эпохи Джанго), "закрыто 4 года назад", и "последний изменен 5 месяцев назад".

Прочитайте обсуждение, это интересно. В принципе, некоторые люди утверждают, что __ne следует добавить в то время как другие говорят, что exclude() яснее и, следовательно, __ne не следует добавлять.

(Я согласен с первым, потому что последний аргумент примерно эквивалентно тому, что Python не должен иметь !=, потому что он имеет == и not уже...)

7

Последний бит кода исключает все объекты, где x!= 5 и a - True. Попробуйте следующее:

results = Model.objects.filter(a=False, x=5)

Помните, что знак = в приведенной выше строке присваивает False параметру a и номер 5 параметру x. Это не проверка равенства. Таким образом, на самом деле нет никакого способа использовать символ!= В вызове запроса.

  • 3
    Это не на 100% одно и то же, поскольку для этих полей также могут быть значения Null.
  • 0
    Это возвращает только те элементы, которые имеют = False и x = 5, но в вопрос будет включен экземпляр (a = false, x = 4).
Показать ещё 1 комментарий
3

results = Model.objects.filter(a = True).exclude(x = 5)
Генерирует этот sql:
select * from tablex where a != 0 and x !=5
sql зависит от того, как представлено ваше поле True/False, и механизм базы данных. Код django - это все, что вам нужно.
2

То, что вы ищете, это все объекты, имеющие либо a=false , либо x=5. В Django | служит в качестве оператора OR между запросами:

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню