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

666

В модели QuerySets Django, я вижу, что есть __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)
MikeN
источник
75
Сработали бы результаты = Model.objects.exclude (a = true) .filter (x = 5)?
Hughdbrown
3
@hughdbrown. Ваш запрос a=trueсначала исключает все, а затем применяет x=5фильтр к остальным. Предполагаемый запрос требует только тех, у кого a=trueи x!=5. Разница в том, что все те, кто с a=trueи x=5также отфильтрованы.
Митчелл ван Зуйлен

Ответы:

690

Может быть, объекты 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>, ...]
Дейв Фогт
источник
16
@ JCLeitão: см. Также ответ @ d4nt ниже для более понятного синтаксиса.
Пол Д. Уэйт
612

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

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

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

d4nt
источник
2
@ d4nt: я могу ошибаться, но я думаю, что запрос должен бытьresults = Model.objects.filter(a=true).exclude(x=5)
Таранджит
1
@Taranjeet: Я думаю, что вы неправильно прочитали исходный запрос. Версия d4nt верна, потому что OP хотел исключить (a = True) и отменить исключение x = 5 (т.е. включить его).
Чак
3
Я думаю, что это неправильно, потому что экземпляр (x = 4, a = false) будет ошибочно исключен.
RemcoGerlich
4
@danigosa Это не кажется правильным. Я просто попробовал это сам, и порядок excludeи filterзвонки не имели никакого значения. Порядок условий в WHEREпункте меняется, но как это имеет значение?
coredumperror
4
Порядок исключения @danigosa и фильтра не имеет значения.
EralpB
132

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, как предлагает Дейв Фогт, и используя filter()или, exclude()как Джейсон Бейкер предлагает, вы получите именно то, что вам нужно для любого возможного запроса.

SingleNegationElimination
источник
спасибо, это круто Я использовал что-то вроде этого, tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$')и это работает.
suhailvs
@suhail, учтите, что не все базы данных поддерживают этот синтаксис регулярных выражений :)
Anoyz
2
я в icontains, iexactи подобное расшифровывается как «игнорировать чувствительность к регистру». Это не для "обратного".
Плющ растет
Стоит отметить, что когда вы используете exclude()несколько терминов, вы можете составить предложение с ORоператором, например exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2)), чтобы исключить результаты при обоих условиях.
Клапас
98

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

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

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)
Дмитрий Михайлов
источник
88

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

  1. Цепь excludeиfilter

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

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

    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 и позволяет пользовательский LookUp как обычно:

    results = Model.objects.exclude(a=True, x__ne=5)
ilse2005
источник
1
object_list = QuerySet.filter (~ Q (a = True), x = 5): не забудьте оставить все остальные условия, не содержащие Q, после тех, которые содержат Q.
Бхуми
1
@MichaelHoffmann: A) после исключения вы будете фильтровать меньший набор данных, используя ~ Q, так что это более эффективно. Б), вероятно, последовательность не работает .. Дан знаю .. Дун помните!
Бхуми
41

В то время как с моделями, вы можете фильтровать с =, __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')
Dami
источник
24

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

У системы отслеживания проблем Django есть замечательная запись № 5763 под названием «Queryset не имеет« неравного »оператора фильтра» . Это примечательно тем, что (по состоянию на апрель 2016 года) он был «открыт 9 лет назад» (в каменном веке Джанго), «закрыт 4 года назад» и «последний изменился 5 месяцев назад».

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

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

Лутц Пречелт
источник
22

Использование exclude и filter

results = Model.objects.filter(x=5).exclude(a=true)
Джинси Мариам
источник
18

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

results = Model.objects.exclude(a=true).filter(x=5)
outoftime
источник
8

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

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

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

Джейсон Бейкер
источник
3
Это не на 100% одно и то же, поскольку для этих полей также могут быть значения Null.
MikeN
Это возвращает только те элементы, которые имеют = False и x = 5, но в вопрос будет включен экземпляр (a = false, x = 4).
RemcoGerlich
1
results = Model.objects.filter(a__in=[False,None],x=5)
Джереми
8

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

М. Дасн
источник
8

Django-model-values (раскрытие: автор) обеспечивает реализацию поиска NotEqual , как в этом ответе . Это также обеспечивает синтаксическую поддержку для этого:

from model_values import F
Model.objects.exclude(F.x != 5, a=True)
А. Коади
источник
6

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

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)
Gerard
источник
5

Это даст желаемый результат.

from django.db.models import Q
results = Model.objects.exclude(Q(a=True) & ~Q(x=5))

для не равных вы можете использовать ~на равный запрос. очевидно, Qможет быть использован для достижения равного запроса.

Милад Ходабандехлоо
источник
Пожалуйста, проверьте редактирование; с помощью «и» в Q(a=True) and ~Q(x=5)будет вычисляться в ~Q(x=5)качестве аргументов .exclude. Пожалуйста, прочитайте: docs.python.org/3/reference/expressions.html#boolean-operations и docs.python.org/3/reference/… .
tzot
2

Остерегайтесь множества неправильных ответов на этот вопрос!

Логика Джерарда верна, хотя он вернет список, а не набор запросов (что может не иметь значения).

Если вам нужен набор запросов, используйте Q:

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
Марк Бейли
источник