Фильтрация пустых или пустых имен в наборе запросов

463

У меня есть first_name, last_nameи alias( по желанию) , который мне нужно искать. Итак, мне нужен запрос, чтобы дать мне все имена, для которых установлен псевдоним.

Только если бы я мог сделать:

Name.objects.filter(alias!="")

Итак, что эквивалентно вышесказанному?

un33k
источник

Ответы:

841

Вы могли бы сделать это:

Name.objects.exclude(alias__isnull=True)

Если вам необходимо исключить нулевые значения и пустые строки, предпочтительный способ сделать это - связать воедино следующие условия:

Name.objects.exclude(alias__isnull=True).exclude(alias__exact='')

Объединение этих методов в одно целое проверяет каждое условие независимо: в приведенном выше примере мы исключаем строки, в которых aliasесть либо пустая, либо пустая строка, поэтому вы получаете все Nameобъекты, которые имеют не пустое и не пустое aliasполе. Сгенерированный SQL будет выглядеть примерно так:

SELECT * FROM Name WHERE alias IS NOT NULL AND alias != ""

Вы также можете передать несколько аргументов в один вызов exclude, что позволит исключить только те объекты, которые соответствуют каждому условию:

Name.objects.exclude(some_field=True, other_field=True)

Здесь строки, в которых some_field и other_field true, исключаются, поэтому мы получаем все строки, в которых оба поля не являются истинными. Сгенерированный код SQL будет выглядеть примерно так:

SELECT * FROM Name WHERE NOT (some_field = TRUE AND other_field = TRUE)

В качестве альтернативы, если ваша логика более сложна, вы можете использовать объекты Django Q :

from django.db.models import Q
Name.objects.exclude(Q(alias__isnull=True) | Q(alias__exact=''))

Для получения дополнительной информации см. Эту страницу и эту страницу в Django документах.

В качестве отступления: мои примеры SQL - просто аналогия - фактически сгенерированный код SQL, вероятно, будет выглядеть иначе. Вы получите более глубокое понимание того, как работают запросы Django, фактически посмотрев SQL, который они генерируют.

Саша Чедыгов
источник
5
Я считаю, что ваше редактирование неверно: фильтр цепочки НЕ создает автоматически SQL OR(только в этом случае), он производит SQL AND. См. Эту страницу для справки: docs.djangoproject.com/en/dev/topics/db/queries/… Преимущество цепочки заключается в том, что вы можете смешивать excludeи filterмоделировать сложные условия запроса. Если вы хотите смоделировать реальный SQL, ORвы должны использовать объект Django Q: docs.djangoproject.com/en/dev/topics/db/queries/… Пожалуйста, отредактируйте ваши изменения, чтобы отразить это, так как ответ серьезно вводит в заблуждение ,
Шези
1
@shezi: Я имел в виду это скорее как аналогию - я не имел в виду, что реальный код SQL гарантированно использует ORдля объединения условий. Я отредактирую свой ответ, чтобы уточнить.
Саша Чедыгов
1
Имейте в виду, что существуют разные способы представления этой логики - например, NOT (A AND B)эквивалентно NOT A OR NOT B. Я думаю, что это сбивает с толку новых разработчиков Django, которые знают SQL, но не знакомы с ORM.
Саша Чедыгов
3
Я знаю закон Де Моргана, и это моя точка зрения: ваш пример работает только потому, что он использует преимущество, чтобы превратить ANDпервый запрос в ORпотому что вы используете exclude. В общем случае, это, вероятно , правильнее было бы думать цепочки , как THEN, например exclude(A) THEN exclude(B). Извините за резкий язык выше. Ваш ответ действительно хорош, но я беспокоюсь о том, что новые разработчики воспримут ваш ответ слишком широко.
Шези
2
@shezi: достаточно справедливо. Я согласен, что лучше думать об этом в терминах Django, а не в терминах SQL, я просто подумал, что представление цепочки с точки зрения ANDи ORможет быть полезным для тех, кто приезжает в Django из фона SQL. Для более глубокого понимания Django, я думаю, документы справляются лучше, чем я.
Саша Чедыгов
49
Name.objects.filter(alias__gt='',alias__isnull=False)
jbofill
источник
2
Я не уверен, но я думаю, что alias__isnull=Falseусловие является избыточным. Если поле Nullобязательно будет исключено первым предложением?
Bobble
Помимо моего предыдущего комментария / вопроса, я думаю, что позитивной логике здесь легче следовать, чем в некоторых других ответах.
Bobble
@Bobble, который будет зависеть от реализации базы данных - порядок делегирован для базы данных
wpercy
alias__gtбыла единственная вещь, которая работала для столбцов типа JSON, где я хотел исключить пустые строки из типа JSON {'something:''}. Так работает синтаксис:jsoncolumnname__something__gt=''
bartgras
38

Во-первых, документы Django настоятельно рекомендуют не использовать значения NULL для строковых полей, таких как CharField или TextField. Прочитайте документацию для объяснения:

https://docs.djangoproject.com/en/dev/ref/models/fields/#null

Решение: я думаю, что вы также можете объединить методы в QuerySets. Попробуй это:

Name.objects.exclude(alias__isnull=True).exclude(alias="")

Это должно дать вам набор, который вы ищете.

b3ng0
источник
5

Из Джанго 1.8,

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)
Химический программист
источник
5
Это похоже на «то, что вы можете сделать», а не то, что вы должны делать. Это значительно увеличивает сложность запроса за две простые проверки.
Оли
3

Чтобы избежать распространенных ошибок при использовании exclude, помните:

Вы не можете добавить несколько условий в блок exclude (), например filter. Чтобы исключить несколько условий, вы должны использовать несколько exclude ()

пример

Неверно :

User.objects.filter (email='example@example.com '). Exclude (profile__nick_name =' ', profile__avt =' ')

Исправить :

User.objects.filter (email='example@example.com '). Исключить (profile__nick_name =' '). Исключить (profile__avt =' ')

HoangYell
источник
0

Вы можете просто сделать это:

Name.objects.exclude(alias="").exclude(alias=None)

Это действительно так просто. filterиспользуется для сопоставления и excludeсопоставления всего, кроме того, что указано. Это оценило бы в SQL как NOT alias='' AND alias IS NOT NULL.

Тим Тисдалл
источник
Это неверно Цель этого вопроса - исключить из запроса псевдонимы empty ( alias="") и NULL ( alias=None). Ваш будет включать в себя случаи с Name(alias=None).
Damon
@damon - я отвечал на то, что было эквивалентно, .filter(alias!="")но не названию. Я отредактировал свой ответ. Однако символьные поля не должны разрешать значения NULL и использовать пустую строку для ненулевого значения (согласно соглашению).
Тим
-1

это еще один простой способ сделать это.

Name.objects.exclude(alias=None)
ImadOS
источник
Noneэто не то же самое, что "".
Тим