Курс по Django: https://stepik.org/a/183363
Архив проекта: 21_sitewomen.zip
Продолжаем
знакомиться с базовыми возможностями ORM Django. Снова перейдем
в консоль shell_plus:
python
manage.py shell_plus --print-sql
(в оболочке shell_plus модели
импортируются автоматически).
На данный момент
мы с вами научились создавать, добавлять новые записи в таблицу БД, а также
выбирать одну или несколько записей по определенному критерию. Однако довольно
часто бывает необходимость, при выборке дополнительно выполнять сортировки
записей по указанному полю. Для этого используется метод order_by(), например,
следующим образом:
Women.objects.all().order_by('title')
Получаем SQL-запрос, в
котором появляется новое ключевое слово ORDER BY с флагом ASC (сортировка по
возрастанию). На выходе получим список:
<QuerySet
[<Women: Анджелина Джоли>, <Women: Джулия Робертс>, <Women:
Екатерина Гусева>, <Women: Кира Найтли>, <Women: Ума Турман>,
<Women: Энн Хэтэуэй>]>
Или, ту же самую
команду можно записать в виде:
Women.objects.order_by('title')
Результат будет
абсолютно тем же самым.
Вообще, метод order_by() можно
применять к любой коллекции QuerySet. Например, с помощью фильтра
отобрать несколько записей, а затем, выполнить их фильтрацию:
Women.objects.filter(pk__lte=4).order_by('title')
Здесь отбираются
все записи, у которых id меньше или равен 4 и сортируются по
полю title в порядке
возрастания (используется лексикографическое сравнение строк). Этот пример
показывает, как методы можно цепочкой выполнять друг за другом: сначала выбрали
записи по условию, а затем их отсортировали. Точно также по цепочке можно выполнять
многие другие методы ORM.
Если нам нужно
изменить порядок сортировки на противоположный, то перед именем поля достаточно
поставить знак минус:
Women.objects.order_by('-time_update')
В этом случае в SQL-запросе после
ключевого слова ORDER BY появляется флаг
DESC, означающий
сортировку по убыванию.
Вложенный класс Meta
При
необходимости, в любой модели мы можем определить некоторые глобальные
настройки. Например, по умолчанию выполнять сортировку статей по убыванию
времени их создания. Для этого внутри класса модели следует прописать еще один
класс Meta и в нем
определить атрибут ordering следующим образом:
class Women(models.Model):
...
class Meta:
ordering = ['-time_create']
indexes = [
models.Index(fields=['-time_create']),
]
def __str__(self):
return self.title
И дополнительно
здесь сразу указано, что это поле должно быть индексируемым, чтобы сортировка
выполнялась быстрее. Вообще у этого класса множество разных атрибутов.
Подробнее о них можно посмотреть на следующей странице документации:
https://docs.djangoproject.com/en/4.2/ref/models/options/
Если теперь
снова зайти в консоль shell_plus:
python
manage.py shell_plus --print-sql
то при
извлечении всех записей:
они будут
следовать в обратном порядке согласно атрибуту ordering класса Meta.
Изменение записей
Следующим шагом
посмотрим, как можно с помощью команд ORM Django менять данные в
уже существующих записях таблицы БД. В самом простом случае, для изменения какой-либо
записи, ее можно сначала прочитать из БД, например, с помощью метода get():
wu = Women.objects.get(pk=2)
Затем, присвоить
атрибутам объекта Women другие значения, например:
wu.title = 'Марго Робби'
wu.content = 'Биография Марго Робби'
Сохраняем новые
данные:
и в таблице
видим, что вторая запись содержит новую, измененную информацию. При этом
последний SQL-запрос имеет следующий
вид:
'UPDATE
"women_women" SET "title" = \'Марго Робби\',
"content" = \'Биография Марго Робби\',
"photo" = \'\', "time_create" = \'2021-01-03
09:27:56.511898\', "time_update" = \'2021-01-03 11:57:06.800768\',
"is_published" = 1 WHERE "women_women"."id" = 2'
Это первый
подход к изменению записей, когда у нас уже имеется объект, который нужно
изменить. Но что если нам нужно, например, у всех записей поле is_published установить в
ноль? Как это сделать? В этом случае нам поможет специальный метод update(), который
можно использовать следующим образом:
Women.objects.update(is_published=0)
В итоге, поле is_published для всех
записей будет установлено в ноль. Или, можно поменять это же значение только
для первых четырех записей, допустим, установить в единицу. Если попробовать
это сделать через срезы:
Women.objects.all()[:4].update(is_published=1)
то получим
ошибку. Метод update() нельзя
комбинировать со срезами. Но после метода filter() его можно
вызывать. Поэтому следующая команда даст нужный нам результат:
Women.objects.filter(pk__lte=4).update(is_published=1)
Также получим
ошибку, если метод update() вызвать для объекта класса Women, например, так:
Women.objects.get(pk=5).update(is_published=1)
И это понятно,
так как для изменения записей в SQL-запросах на первом месте должно стоять
ключевое слово UPDATE, а при формировании выборки – ключевое
слово SELECT. То есть, это
два разных типа запросов и комбинировать их нельзя. Отсюда и получаем ошибку их
выполнения.
Удаление записей
Наконец,
последняя базовая операция – удаление записей, выполняется аналогично
изменению. То есть, сначала нужно выбрать те записи, что мы собираемся удалить,
например, вот так:
wd = Women.objects.filter(pk__gte=5)
А, затем,
выполняем для них метод delete():
Все, записи с id равным 5 и 6
были удалены из таблицы women.
На этом занятии
мы лишь в целом рассмотрели некоторые возможности ORM Django. Более
детальную информацию можно почитать на странице документации:
docs.djangoproject.com/en/4.2/topics/db/queries/
Курс по Django: https://stepik.org/a/183363