Преобразование 'not in' SQL-запроса в синтаксис Django
Быстрый ответ
В Django фильтрация объектов модели по наличию или отсутствию конкретных значений в списке осуществляется с помощью методов filter
и exclude
. Они используются с оператором __in
.
Примеры использования:
# Выборка объектов, удовлетворяющих условию:
YourModel.objects.filter(field__in=[values])
# Исключение объектов, не удовлетворяющих условию:
YourModel.objects.exclude(field__in=[values])
- Оператор
__in
совместим со всеми перечислительными типами данных. - Вместо
YourModel
подставьте название вашей модели. field
и[values]
замените на имя поля модели и список значений, предназначенных для фильтрации или исключения.
Использование подзапросов для исключений
Для того чтобы исключить записи из одной таблицы на основе условий в другой в Django, можно поступить следующим образом:
leave_out_ids = Table2.objects.filter(your_condition).values_list('id', flat=True)
Table1.objects.exclude(id__in=leave_out_ids)
Уточнения:
your_condition
определяет фильтр для таблицыTable2
.exclude
исключает из таблицыTable1
записи, чейid
присутствует в спискеleave_out_ids
.- Параметр
flat=True
позволяет возвратить список id вместо списка кортежей.
Обработка связанных моделей
При наличии связи через ForeignKey воспользуйтесь следующим синтаксисом:
YourModel.objects.exclude(related_table__field=value)
Таким образом, мы исключаем объекты, связанные с моделью, где поле соответствует указанному значению value
.
Формирование сложных запросов при помощи Q-объектов
Для построения сложных запросов применяются Q-объекты:
from django.db.models import Q
condition = ~Q(related_table__field=value)
YourModel.objects.filter(condition)
- Знак
~
инверсирует условие Q-объекта. - Q-объекты можно сохранять в переменные для простоты восприятия кода.
Исполнение собственных SQL-запросов и рекомендации по оптимизации производительности
В Django можно выполнить кастомный SQL-запрос через objects.extra
:
YourModel.objects.extra(where=["field NOT IN (SELECT field FROM Table2 ...)"])
Важно помнить следующее:
- Не забывайте про защиту от SQL-инъекций.
- Оптимизация SQL-запросов повысит производительность.
Визуализация
Для наглядного понимания принципа работы фильтров in/not in
, рассмотрим пример:
Сокровищница (🧳): [Золотая Монета (💰), Серебряное Кольцо (💍), Рубин (🔴)]
Получить определённые предметы можно так:
Treasure.objects.filter(item__in=['💰', '🔴'])
# Собираем все Золотые Монеты и Рубины
Найденные сокровища: [Золотая Монета (💰), Рубин (🔴)]
# Вот они!
Исключить ненужные нам предметы можно следующим образом:
Treasure.objects.exclude(item__in=['💍'])
# Прощай, Серебряное Кольцо!
Оставшиеся сокровища: [Золотая Монета (💰), Рубин (🔴)]
# Звёзды нашего шоу!
Управлять запросами в Django с помощью in/not in
столь же легко.
Разные случаи и их решения
Большой список значений? Не проблема!
При работе с большими списками значений лучше использовать подзапросы:
big_values = range(int(1e6))
YourModel.objects.filter(field__in=big_values)
Такой подход также допустим:
YourModel.objects.exclude(field__in=AnotherModel.objects.all().values_list('field', flat=True))
Будьте осмотрительны с NULL значениями и NOT IN!
Обращение с NULL
значениями и оператором NOT IN
может быть коварным:
YourModel.objects.exclude(field__in=nullable_values)
Для корректной обработки NULL
используйте два условия:
YourModel.objects.exclude(field__in=nullable_values).exclude(field__isnull=True)
Реализация логики 'not in'
Для реализации собственной логики 'not in' можно применять пользовательские операторы сравнения:
from django.db.models import Lookup
class NotIn(Lookup):
lookup_name = 'not_in'
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 NOT IN (%s)' % (lhs, rhs), params
YourModel.objects.get_queryset().filter(field__not_in=[values])
При использовании пользовательских операторов не забывайте о читаемости и производительности кода.
Полезные материалы
- Справочник по API QuerySet, Django Documentation – описание использования
__in
в QuerySets Django. - Создание запросов, Django Documentation – детальное руководство по созданию запросов в Django.
- Справочник по API QuerySet, Django Documentation – основы применения
exclude()
в Django. - ORM Django (Querysets), HonKit – путь к освоению ORM и QuerySets в Django.
- Учебник Django, часть 3: Использование моделей, Mozilla – инструкция по использованию моделей Django.
- Как просмотреть исходные SQL-запросы, выполняемые Django?, Stack Overflow – советы по просмотру SQL-запросов в Django.
- Объект Q, возвращающий false, Stack Overflow – обсуждение создания Q-объектов, всегда возвращающих ложное значение.