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

В 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)

person MikeN    schedule 26.03.2009    source источник
comment
Сработало бы results = Model.objects.exclude (a = true) .filter (x = 5)?   -  person hughdbrown    schedule 28.07.2009
comment
@hughdbrown. Нет. Ваш запрос сначала исключает все a=true, а затем применяет фильтр x=5 к оставшимся. Предполагаемый запрос требовал только тех, у которых есть a=true и x!=5. Разница в том, что все те, у кого есть a=true и x=5, также отфильтровываются.   -  person Mitchell van Zuylen    schedule 15.02.2018


Ответы (15)


Вы можете использовать объекты Q для этого. Их можно инвертировать с помощью оператора ~. и объединены так же, как и обычные выражения Python:

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

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

вернет все записи, кроме одной (й) с 3 в качестве идентификатора:

[<Entry: Entry object>, <Entry: Entry object>, <Entry: Entry object>, ...]
person Dave Vogt    schedule 20.07.2009
comment
Есть ли причина делать Entry.objects.filter(~Q(id=3)), а не Entry.objects.exclude(id=3)? - person Bob Whitelock; 14.12.2020

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

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

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

person d4nt    schedule 09.11.2010
comment
@ d4nt: Возможно, я ошибаюсь, но я думаю, что запрос должен быть results = Model.objects.filter(a=true).exclude(x=5) - person Taranjeet; 02.09.2015
comment
@Taranjeet: Думаю, вы неправильно прочитали исходный запрос. Версия d4nt верна, потому что OP хотел исключить (a = True) и отменить исключение x = 5 (т.е. включить его). - person Chuck; 16.09.2015
comment
Я думаю, что это неправильно, потому что экземпляр (x = 4, a = false) был бы ошибочно исключен. - person RemcoGerlich; 17.11.2015
comment
Просто чтобы сказать, порядок имеет значение, поэтому objects.exclude(**filter1).filter(**filter2) дает результаты, отличные от objects.filter(**filter1).exclude(**filter2), а ~ Q всегда будет получать правильное отрицание внутри objects.filter(**filter_with_Q) - person danius; 06.01.2016
comment
@danigosa Это кажется неправильным. Я просто пробовал это сам, и порядок вызовов exclude и filter не имел никакого значения. Порядок условий в предложении WHERE меняется, но какое это имеет значение? - person coredumperror; 07.04.2016
comment
@danigosa порядок исключения и фильтрации не имеет значения. - person EralpB; 05.09.2017
comment
Это может не сработать, если вы фильтруете поля связанных объектов. - person dhill; 07.06.2019
comment
Это неверный ответ. вы хотите исключить все строки, где x не равно 5 - Нет, запрашивающий хочет исключить строки, в которых (x не равно 5 И a истинно). ! (x! = 5 И a) тогда и только тогда. (! (x! = 5) ИЛИ! a) [Де Морган] тогда и только тогда. (x == 5 OR! a) [путем двойного отрицания] Но это решение предоставляет все строки, где (x == 5 AND! a) Что, конечно, отличается в случаях, когда (x == 5 AND a) или когда ( х! = 5 И! а) - person talz; 26.01.2021

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

exact
iexact
contains
icontains
in
gt
gte
lt
lte
startswith
istartswith
endswith
iendswith
range

date
year
iso_year
month
day
week
week_day
iso_week_day
quarter
time
hour
minute
second

isnull
regex
iregex

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

person SingleNegationElimination    schedule 20.07.2009
comment
спасибо, это круто. Я использовал что-то вроде этого tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$'), и оно работает. - person suhailvs; 11.09.2013
comment
@suhail, учтите, что не все базы данных поддерживают этот синтаксис регулярного выражения :) - person Anoyz; 12.07.2016
comment
i в icontains, iexact и подобных означает игнорирование чувствительности к регистру. Это не обратное. - person Ivy Growing; 06.05.2017
comment
Стоит отметить, что когда вы используете exclude() с несколькими терминами, вы можете составить предложение с помощью оператора OR, например exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2)), чтобы исключить результаты при обоих условиях. - person clapas; 25.08.2017

Есть три варианта:

  1. Цепочка exclude и filter

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

    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 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
    

    Что можно использовать как обычно:

    results = Model.objects.exclude(a=True, x__ne=5)
    
person ilse2005    schedule 24.02.2016
comment
object_list = QuerySet.filter (~ Q (a = True), x = 5): не забудьте сохранить все остальные условия, не содержащие Q, после тех, которые содержат Q. - person Bhumi Singhal; 06.06.2017
comment
@MichaelHoffmann: A) вы затем отфильтруете меньший набор данных после исключения, используя ~ Q, так что это будет более эффективно. Б) вероятно, обратная последовательность не работает .. не знаю .. не помню! - person Bhumi Singhal; 28.02.2019
comment
интересно, есть ли разница в производительности в 1 против 2 - person Anupam; 13.08.2020
comment
ПРИМЕЧАНИЕ: exclude добавит кое-что к предложению WHERE, так что это может быть довольно эффективным. См. docs.djangoproject.com/en/3.2/ref/models/ querysets / # exclude. @Anupam - person dfrankow; 14.06.2021

Создать собственный поиск легко, есть пример __ne поиска в Официальная документация Django.

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

from django.db.models import 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

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

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

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

results = Model.objects.exclude(a=True, x__ne=5)
person Dmitrii Mikhailov    schedule 24.03.2015

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

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

from django.db.models import Q
object_list = QuerySet.filter(~Q(field='not wanted'), field='wanted')
person Dami    schedule 18.01.2011

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

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

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

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

person Lutz Prechelt    schedule 21.04.2016
comment
Это не ожидаемое дизайнерское решение, они решили не делать этого 8 лет назад. - person Boris; 13.11.2020

Использование исключения и фильтра

results = Model.objects.filter(x=5).exclude(a=true)
person jincy mariam    schedule 12.07.2018
comment
Чем это отличается от ответа @d4nt, оставшегося на 8 лет раньше вашего и ответ @ outoftime, сделанный на 3 года раньше этого? - person Boris; 12.11.2020

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

results = Model.objects.exclude(a=true).filter(x=5)
person outoftime    schedule 25.09.2015
comment
Чем это отличается от ответа @d4nt, сделанного на 5 лет раньше вашего? - person Boris; 12.11.2020

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

from model_values import F
Model.objects.exclude(F.x != 5, a=True)
person A. Coady    schedule 13.01.2018

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

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

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

person Milad Khodabandehloo    schedule 29.09.2019
comment
Пожалуйста, проверьте правку; использование «и» в Q(a=True) and ~Q(x=5) даст результат ~Q(x=5) в качестве аргумента для .exclude. Прочтите: docs.python.org/3/reference/expressions.html # boolean-operations и docs.python.org / 3 / ссылка /. - person tzot; 11.10.2019

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

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

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

person Jason Baker    schedule 26.03.2009
comment
Это не на 100% одно и то же, поскольку для этих полей также могут быть нулевые значения. - person MikeN; 20.07.2009
comment
Это возвращает только те элементы, которые имеют a = False и x = 5, но в вопрос будет включен экземпляр (a = false, x = 4). - person RemcoGerlich; 17.11.2015

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

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)
person Gerard    schedule 27.06.2016

Следите за множеством неправильных ответов на этот вопрос!

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

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

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
person Mark Bailey    schedule 14.03.2019
comment
[...] Джерарда вернет список, а не набор запросов - это неправда. он возвращает набор запросов. И ваш ответ совпадает с принятым ответом. - person Boris; 12.11.2020

Если нам нужно исключить / отрицать на основе подзапроса, который мы можем использовать,

Условный фильтр:

Когда условное выражение возвращает логическое значение, его можно использовать непосредственно в фильтрах. Здесь non_unique_account_type возвращает логическое значение. Но, тем не менее, мы можем использовать его в фильтре.

>>> non_unique_account_type = Client.objects.filter(
...     account_type=OuterRef('account_type'),
... ).exclude(pk=OuterRef('pk')).values('pk')
>>> Client.objects.filter(~Exists(non_unique_account_type))

В терминах SQL он оценивается как:

SELECT * FROM client c0
WHERE NOT EXISTS (
  SELECT c1.id
  FROM client c1
  WHERE c1.account_type = c0.account_type AND NOT c1.id = c0.id
)
person Siva Sankar    schedule 13.06.2021