Выражения Q() инкапсулирует SQL выражение внутри объекта Python. Объекты Q() наиболее часто используются для построения сложных запросов к базе данных, связывая вместе несколько выражений, используя операторы AND & и OR |:
Например с помощью следующего запроса, мы можем получить всех сотрудников, имена которых начинаются на "Ja" или "Jo".
Employee.objects.filter(Q(first_name__startswith='Ja') | Q(first_name__startswith='Jo'))
В Django вы можете использовать объект Q с диапазоном, чтобы проверить, не находится ли значение в диапазоне, для этого вы можете использовать Q объект и ~ оператор:
Entity.objects.filter(~Q(field_name__range=(low_value,high_value)))
Например, вы можете найти сотрудников с идентификатором, не входящим в диапазон (3,5):
Employee.objects.filter(~Q(id__range=(3,5)))
Обычно вы используете подзапрос с in оператором, а не список литеральных значений. Например, вы найдете всех сотрудников в отделах IT и Testing следующим образом:
departments = Department.objects.filter(Q(name='IT') | Q(name='Testing'))
Employee.objects.filter(department__in=departments)
Как это работает.
Сначала мы получаем отделы с именами IT или Testing:
departments = Department.objects.filter(Q(name='IT') | Q(name='Testing'))
Далее мы передаем department QuerySet оператору in:
Employee.objects.filter(department__in=departments)
За кулисами Django выполняет запрос с IN оператором, который сопоставляет идентификатор отдела со списком идентификаторов отделов из списка:
SELECT "hr_employee"."id",
"hr_employee"."first_name",
"hr_employee"."last_name",
"hr_employee"."contact_id",
"hr_employee"."department_id"
FROM "hr_employee"
WHERE "hr_employee"."department_id" IN (
SELECT U0."id"
FROM "hr_department" U0
WHERE (U0."name" = 'IT' OR U0."name" = 'Testing')
)
Оператор NOT отрицает IN оператор. Оператор NOT IN возвращает True, если значение отсутствует в списке значений:
field_name NOT IN (v1, v2, ...)
Для выполнения NOT IN в Django вы можете использовать Q объект и ~ оператор:
~Q(field_name__in=(v1,v2,..))
Например, следующий код находит сотрудников, чей идентификатор отдела не равен 2 или 3:
Employee.objects.filter(~Q(department_id__in=(2,3)))
В качестве альтернативы вы можете использовать exclude() метод вместо filter() метода:
Employee.objects.exclude(department_id__in=(2,3))