Фільтрування порожніх або NULL імен у наборі запитів


463

У мене є first_name, last_nameі alias( по бажанню) , який мені потрібно шукати. Отже, мені потрібен запит, щоб дати мені всі імена, у яких встановлено псевдонім.

Тільки якщо я міг би зробити:

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

Отже, що рівнозначно вище?

Відповіді:


839

Ви можете це зробити:

Name.objects.exclude(alias__isnull=True)

Якщо вам потрібно виключити нульові значення та порожні рядки, кращим способом зробити це - з'єднати між собою такі умови, як:

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

Об'єднання цих методів разом, в основному, перевіряє кожну умову незалежно: у наведеному вище прикладі ми виключаємо рядки, де aliasє або null, або порожній рядок, тому ви отримуєте всі Nameоб'єкти, які мають не-null, не порожнє 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 є справжніми прибудуть виключені, тому ми отримуємо всі рядки , в яких обидва поля НЕ відповідає дійсності. Створений код SQL буде виглядати приблизно так:

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

Крім того, якщо ваша логіка більш складна, ніж ви, ви можете використовувати Q-об'єкти Django :

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/…. Будь ласка, відредагуйте свою редакцію, щоб відобразити це, оскільки відповідь сильно оманливий, оскільки вона є. .
shezi

1
@shezi: Я мав на увазі це більше як аналогія - я не мав на увазі, що фактичний код SQL гарантовано використовує "f" для змикання ORумов. Я відредагую свою відповідь, щоб уточнити.
Саша Чедигов

1
Майте на увазі, що існують різні способи представити цю логіку - наприклад, NOT (A AND B)це рівнозначно NOT A OR NOT B. Я думаю, що це заплутує нових розробників Django, які знають SQL, але незнайомі з ORM.
Саша Чедигов

3
Я знаю закон Де Моргана, і саме це я можу сказати: Ваш приклад працює лише тому, що він корисний для того, щоб перетворити ANDперший запит у те, ORщо ви використовуєте exclude. У загальному випадку, мабуть, правильніше думати про ланцюг як а THEN, тобто exclude(A) THEN exclude(B). Вибачте за сувору мову вище. Ваша відповідь справді хороша, але я переживаю, що нові розробники сприймуть вашу відповідь занадто загально.
shezi

2
@shezi: Досить справедливо. Я погоджуюсь, що краще думати про це в термінах Джанго, а не в термінах SQL, я просто подумав, що представлення ланцюжка в термінах ANDі ORможе бути корисним для того, хто приходить до Джанго зі складу SQL. Для глибшого розуміння Джанго, я думаю, що документи роблять кращу роботу, ніж я можу.
Саша Чедигов

49
Name.objects.filter(alias__gt='',alias__isnull=False)

2
Я не впевнений, але я вважаю, що alias__isnull=Falseстан є зайвим. Якщо поле, Nullбезумовно, буде виключено першим пунктом?
Боббл

Окрім попереднього коментаря / запитання, я думаю, що позитивну логіку тут простіше прослідкувати, ніж у деяких інших відповідях.
Боббл

@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="")

Це повинно дати вам набір, який ви шукаєте.


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 , пам’ятайте:

Ви не можете додати кілька умов у блок виключення (), як filter. Щоб виключити декілька умов, потрібно використовувати кілька виключити ()

Приклад

Неправильно :

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

Правильно :

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


0

Ви можете просто зробити це:

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

Це насправді так просто. filterвикористовується для узгодження і excludeмає відповідати всьому, окрім того, що він вказує. Це оцінюється в SQL як NOT alias='' AND alias IS NOT NULL.


Це неправильно. Питання має на меті виключити порожні ( alias="") та NULL ( alias=None) псевдоніми із запиту. Ваші включатимуть екземпляри з Name(alias=None).
прокляття

@damon - я відповідав, що було рівнозначно, .filter(alias!="")але не назві. Я відредагував свою відповідь. Однак поля символів не повинні дозволяти значенням NULL і використовувати порожню рядок для не значення (згідно з умовами).
Тім

-1

це ще один простий спосіб зробити це.

Name.objects.exclude(alias=None)

Noneце не те саме, що "".
Тім
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.