Курс по Django: https://stepik.org/a/183363
Начиная с этого
занятия, мы с вами немного углубимся в ORM Django, чтобы вы лучше
представляли себе его возможности и могли применять их на практике. Некоторое
введение у нас с вами уже есть, в частности, умеем работать с записями
отдельных таблиц, а именно:
- Create
– создавать записи;
- Read
– читать
записи;
- Update
– менять
записи;
- Delete
– удалять
записи.
Набор команд из
этой серии часто объединяют в аббревиатуру CRUD и им были
посвящены первые занятия по ORM. Также мы уже умеем работать со
связанными таблицами и знаем три вида связей:
- one-to-one
(один
к одному);
- many-to-one (многие к
одному);
- many-to-many (многие ко
многим).
Вообще, ORM Django имеет очень
богатый функционал и вам вряд ли понадобится переходить на уровень SQL-запросов, так
как все можно сделать на уровне этого API. Кроме того, начинающим
разработчикам уровень ORM позволит писать грамотные и
оптимизированные запросы к БД любого типа: SQLite, MySQL, PostgreSQL, Oracle, то есть,
приложение будет совершенно независимым от типа СУБД. Все это и привело к тому,
что сейчас, в основном, используются различные ORM при работе с
таблицами БД. Подробную информацию обо всем этом можно посмотреть в документации:
https://docs.djangoproject.com/en/4.2/#the-model-layer
В частности
ссылка «методы QuerySet»:
https://docs.djangoproject.com/en/4.2/ref/models/querysets/
приводит нас на
страницу с описанием различных методов, которые доступны в ORM Django. Как всегда,
советую с ними подробно ознакомиться, чтобы грамотно их использовать в своих
проектах. Чаще всего используются методы: filter, all, get, о которых мы
уже подробно говорили. Также здесь вы найдете, так называемые, lookup’ы, которые
позволяют формировать различные условия для выборки записей, и ниже
представлены функции агрегации.
На этом занятии
мы продолжим изучать команды ORM Django и для этого я
перейду в терминал и запущу консоль:
python
manage.py shell_plus --print-sql
Ранее мы с вами
говорили, что если в методе filter через запятую указать несколько
именованных аргументов, например, так:
Women.objects.filter(pk__in=[2,5,7,10], is_published=True)
то сформируется SQL-запрос с
условием AND:
WHERE
("women_women"."is_published" AND
"women_women"."id" IN (2, 5, 7, 10))
Если в условии
нужно использовать логическое ИЛИ, а также НЕ, то вместо перечисления критериев
отбора через запятую, следует использовать специальный класс Q. С помощью
этого класса можно описывать более сложные критерии (условия), используя
специальные операторы:
- &
логическое
И (приоритет 2);
- | логическое ИЛИ
(приоритет 1 – самый низкий);
- ~ логическое НЕ
(приоритет 3 – самый высокий).
Давайте
посмотрим, как это все работает. Вначале его нужно импортировать:
from django.db.models import Q
Теперь,
смотрите, если выполнить вот такой запрос:
Women.objects.filter(pk__lt=5, cat_id=2)
то на выходе получим
пустой список, т.к. все записи с id < 5 относятся
к первой категории. Но сейчас мы с помощью класса Q соединим эти
два условия по логическому ИЛИ:
Women.objects.filter(Q(pk__lt=5) | Q(cat_id=2))
То теперь видим
записи, у которых или id<5 или cat_id=2. Кстати,
предыдущий запрос тоже можно записать через класс Q следующим
образом:
Women.objects.filter(Q(pk__lt=5) & Q(cat_id=2))
Ну и, наконец,
если перед классом прописать тильду, то условие превратится в обратное:
Women.objects.filter(~Q(pk__lt=5) | Q(cat_id=2))
Здесь мы
отбираем записи, у которых id >=5 или cat_id=2.
Разумеется, в
методе filter() можно
комбинировать объекты класса Q с обычными аргументами, например, так:
Women.objects.filter(Q(pk__in=[1, 2, 5]) | Q(cat_id=2), title__icontains="ра")
Тогда первые два
выражения будут объединены по ИЛИ, а третье по И:
WHERE
(("women_women"."id" IN (1, 2, 5) OR
"women_women"."cat_id" = 2) AND
"women_women"."title" LIKE '%ра%' ESCAPE '\')
Причем первые
два условия объединены в круглые скобки и образуют одно единое подусловие. То
есть, в методе filter() каждый аргумент, перечисленный через
запятую, образует свое независимое подусловие.
Но, обратите
внимание, мы не можем указывать обычные аргументы до класса Q:
Women.objects.filter(title__icontains="ра", Q(pk__in=[1, 2, 5]) | Q(cat_id=2))
Получим ошибку.
То есть, мы должны такие параметры прописывать либо после класса Q, либо
обертывать аргумент также в класс Q:
Women.objects.filter(Q(title__icontains="ра"), Q(pk__in=[1, 2, 5]) | Q(cat_id=2))
Тогда все
отработает без проблем.
Если же нам
нужно сделать то же самое, но без дополнительных круглых скобок вокруг OR, то следует все
прописать через класс Q следующим образом:
Women.objects.filter(Q(pk__in=[1, 2, 5]) | Q(cat_id=2) & Q(title__icontains="ра"))
Вот так можно использовать
класс Q для описания
запросов с использованием операторов &, | и ~. И всегда помните о
приоритетах операций: сначала выполняется НЕ, затем, И и в последнюю очередь
ИЛИ.
Курс по Django: https://stepik.org/a/183363