0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Практически любое веб-приложение так или иначе работает с базой данных. При этом с системой управления базами данных (СУБД) приложение общается универсальным способом, например, посредством языка SQL.</p>
1
<p>Практически любое веб-приложение так или иначе работает с базой данных. При этом с системой управления базами данных (СУБД) приложение общается универсальным способом, например, посредством языка SQL.</p>
2
<p>Программисту чаще всего хочется иметь некую абстракцию, которая позволяет большую часть времени работать с привычными сущностями языка. Такой абстракцией является ORM. В этом уроке мы разберем необходимый минимум работы с ORM. Подробнее эта тема рассматривается в отдельном курсе.</p>
2
<p>Программисту чаще всего хочется иметь некую абстракцию, которая позволяет большую часть времени работать с привычными сущностями языка. Такой абстракцией является ORM. В этом уроке мы разберем необходимый минимум работы с ORM. Подробнее эта тема рассматривается в отдельном курсе.</p>
3
<h2>ORM</h2>
3
<h2>ORM</h2>
4
<p><strong>ORM (Object-Relational Mapping)</strong>- отображение сущностей предметной области и их взаимосвязей в объекты, удобные для использования программистом.</p>
4
<p><strong>ORM (Object-Relational Mapping)</strong>- отображение сущностей предметной области и их взаимосвязей в объекты, удобные для использования программистом.</p>
5
<p>Разные ORM по-разному подходят к тому, насколько нужно изолировать пользователя от конкретного хранилища. Некоторые полностью скрывают всю работу с базой данных. В этом случае мы пользуемся объектами, изменяем их состояние, а ORM неявно синхронизирует состояние объектов и сущностей в хранилище.</p>
5
<p>Разные ORM по-разному подходят к тому, насколько нужно изолировать пользователя от конкретного хранилища. Некоторые полностью скрывают всю работу с базой данных. В этом случае мы пользуемся объектами, изменяем их состояние, а ORM неявно синхронизирует состояние объектов и сущностей в хранилище.</p>
6
<p>Другие ORM только оборачивают сущности базы данных в структуры языка, но все запросы нужно писать вручную. Это два разных полюса, каждый со своими плюсами и минусами. Авторы Django решили остаться где-то посередине.</p>
6
<p>Другие ORM только оборачивают сущности базы данных в структуры языка, но все запросы нужно писать вручную. Это два разных полюса, каждый со своими плюсами и минусами. Авторы Django решили остаться где-то посередине.</p>
7
<p>Если использовать Django ORM, можно работать с объектами и выполнять вручную их загрузку и сохранение. Однако для этого можно использовать привычные средства языка: итерацию, вызов методов.</p>
7
<p>Если использовать Django ORM, можно работать с объектами и выполнять вручную их загрузку и сохранение. Однако для этого можно использовать привычные средства языка: итерацию, вызов методов.</p>
8
<p>Django же обеспечивает правильную работу нашего приложения с конкретными хранилищами данных. Эта изоляция от конкретного хранилища позволяет использовать разные базы данных в разных условиях. Например, при разработке и тестировании использовать что-то более легковесное, а на релизном сервере применять рабочую базу данных.</p>
8
<p>Django же обеспечивает правильную работу нашего приложения с конкретными хранилищами данных. Эта изоляция от конкретного хранилища позволяет использовать разные базы данных в разных условиях. Например, при разработке и тестировании использовать что-то более легковесное, а на релизном сервере применять рабочую базу данных.</p>
9
<h2>Модель</h2>
9
<h2>Модель</h2>
10
<p>Любая сущность, которая создается внутри приложения, называется<strong>моделью</strong>. Модели в Django лежат в директориях приложений в файлах<em>models.py</em>. Конкретный набор моделей зависит от приложения и может измениться со временем. На Хекслете таких моделей сотни, вот лишь некоторые, с которыми наши пользователи сталкиваются каждый день:</p>
10
<p>Любая сущность, которая создается внутри приложения, называется<strong>моделью</strong>. Модели в Django лежат в директориях приложений в файлах<em>models.py</em>. Конкретный набор моделей зависит от приложения и может измениться со временем. На Хекслете таких моделей сотни, вот лишь некоторые, с которыми наши пользователи сталкиваются каждый день:</p>
11
<ul><li>Пользователь</li>
11
<ul><li>Пользователь</li>
12
<li>Курс</li>
12
<li>Курс</li>
13
<li>Урок</li>
13
<li>Урок</li>
14
<li>Профессия</li>
14
<li>Профессия</li>
15
<li>Упражнение</li>
15
<li>Упражнение</li>
16
<li>Подписка</li>
16
<li>Подписка</li>
17
<li>Участник курса</li>
17
<li>Участник курса</li>
18
<li>Статья в блоге</li>
18
<li>Статья в блоге</li>
19
<li>Топик</li>
19
<li>Топик</li>
20
<li>Комментарий к топику</li>
20
<li>Комментарий к топику</li>
21
<li>Проект</li>
21
<li>Проект</li>
22
</ul><p>Важно не путать понятие модель во фреймворке, с понятием модель в MVC. Последнее - это не про класс, файл, функцию или структуру данных. Это слой приложения, который отвечает за модель предметной области. И это не про базу данных.</p>
22
</ul><p>Важно не путать понятие модель во фреймворке, с понятием модель в MVC. Последнее - это не про класс, файл, функцию или структуру данных. Это слой приложения, который отвечает за модель предметной области. И это не про базу данных.</p>
23
<p>Слово "модель" часто используется в качестве замены словосочетания "Django ORM", поэтому в рамках курсов будет использоваться этот термин. Модель в единственном числе говорит нам о том, что наша предметная область смоделирована с помощью средств фреймворка. Это собирательный образ слоя хранения. При этом отдельные сущности тоже называются моделями - модели поменьше собираются в большую модель всей предметной области.</p>
23
<p>Слово "модель" часто используется в качестве замены словосочетания "Django ORM", поэтому в рамках курсов будет использоваться этот термин. Модель в единственном числе говорит нам о том, что наша предметная область смоделирована с помощью средств фреймворка. Это собирательный образ слоя хранения. При этом отдельные сущности тоже называются моделями - модели поменьше собираются в большую модель всей предметной области.</p>
24
<p>Связь между моделями и таблицами в базе данных: одна таблица - одна модель. В этом плане Django ORM не отходит далеко от схемы базы данных. Всегда можно представить, как фактически представлены данные с точки зрения СУБД. Что очень полезно, когда нужно что-то оптимизировать.</p>
24
<p>Связь между моделями и таблицами в базе данных: одна таблица - одна модель. В этом плане Django ORM не отходит далеко от схемы базы данных. Всегда можно представить, как фактически представлены данные с точки зрения СУБД. Что очень полезно, когда нужно что-то оптимизировать.</p>
25
<h2>Database Engines</h2>
25
<h2>Database Engines</h2>
26
<p>К фактической базе данных Django подключается с помощью<em>Database Engines</em>. Одно приложение может подключаться к нескольким базам данных. Это можно сделать и с помощью разных движков. Но такое случается нечасто. Обычно одна база приходится на одно веб-приложение.</p>
26
<p>К фактической базе данных Django подключается с помощью<em>Database Engines</em>. Одно приложение может подключаться к нескольким базам данных. Это можно сделать и с помощью разных движков. Но такое случается нечасто. Обычно одна база приходится на одно веб-приложение.</p>
27
<p>Описываются базы данных в словаре settings.DATABASES:</p>
27
<p>Описываются базы данных в словаре settings.DATABASES:</p>
28
<ul><li>ENGINE указывает на конкретный движок</li>
28
<ul><li>ENGINE указывает на конкретный движок</li>
29
<li>NAME в случае SQLite хранит имя файла. Для других СУБД это будет имя базы данных в удобном для них формате</li>
29
<li>NAME в случае SQLite хранит имя файла. Для других СУБД это будет имя базы данных в удобном для них формате</li>
30
<li>default - имя базы данных уже для самого Django</li>
30
<li>default - имя базы данных уже для самого Django</li>
31
</ul><p>Когда используется несколько баз данных одновременно и имя другой не указано в коде явно, эта "база данных по умолчанию" используется всегда.</p>
31
</ul><p>Когда используется несколько баз данных одновременно и имя другой не указано в коде явно, эта "база данных по умолчанию" используется всегда.</p>
32
<h2>Описание моделей</h2>
32
<h2>Описание моделей</h2>
33
<p>Модели описываются в модулях<em>models.py</em>. Каждое приложение имеет свой собственный модуль<em>models.py</em>, в котором содержатся описание моделей конкретного приложения.</p>
33
<p>Модели описываются в модулях<em>models.py</em>. Каждое приложение имеет свой собственный модуль<em>models.py</em>, в котором содержатся описание моделей конкретного приложения.</p>
34
<p>Добавим в hexlet_django_blog.article.models следующий код:</p>
34
<p>Добавим в hexlet_django_blog.article.models следующий код:</p>
35
<p>Article - это и есть наша первая модель. У нее четыре поля:</p>
35
<p>Article - это и есть наша первая модель. У нее четыре поля:</p>
36
<ul><li>created_at - для хранения даты и времени создания записи</li>
36
<ul><li>created_at - для хранения даты и времени создания записи</li>
37
<li>updated_at - для хранения даты и времени последнего изменения записи</li>
37
<li>updated_at - для хранения даты и времени последнего изменения записи</li>
38
<li>name- для хранения названия статьи</li>
38
<li>name- для хранения названия статьи</li>
39
<li>body - для хранения текста статьи</li>
39
<li>body - для хранения текста статьи</li>
40
</ul><p>В этом случае мы не описываем поле id, которое обычно является первичным ключом. В<em>models.Model</em>оно уже описано, и нам не нужно это делать дополнительно. Но мы его можем переопределить.</p>
40
</ul><p>В этом случае мы не описываем поле id, которое обычно является первичным ключом. В<em>models.Model</em>оно уже описано, и нам не нужно это делать дополнительно. Но мы его можем переопределить.</p>
41
<p>Со стороны Python всё готово. Но еще нужно сделать так, чтобы соответствующая таблица появилась в базе данных. Для этого необходимо сгенерировать миграцию.</p>
41
<p>Со стороны Python всё готово. Но еще нужно сделать так, чтобы соответствующая таблица появилась в базе данных. Для этого необходимо сгенерировать миграцию.</p>
42
<h2>Миграция</h2>
42
<h2>Миграция</h2>
43
<p>Миграции меняют схему базы данных сообразно тому, как мы меняем модель. В Django работа с миграциями сделана на очень высоком уровне. В том числе - на высоком уровне автоматизации.</p>
43
<p>Миграции меняют схему базы данных сообразно тому, как мы меняем модель. В Django работа с миграциями сделана на очень высоком уровне. В том числе - на высоком уровне автоматизации.</p>
44
<p>Чтобы получить миграцию, выполняем команду:</p>
44
<p>Чтобы получить миграцию, выполняем команду:</p>
45
<p>Когда мы запускаем makemigrations, мы сообщаем Django, что внесли изменения в свои модели, например, создали новую модель. Также мы сообщаем о том, что хотим, чтобы эти изменения сохранились как миграция.</p>
45
<p>Когда мы запускаем makemigrations, мы сообщаем Django, что внесли изменения в свои модели, например, создали новую модель. Также мы сообщаем о том, что хотим, чтобы эти изменения сохранились как миграция.</p>
46
<p><strong>Миграции</strong>- это описания изменений в наших моделях, и в дальнейшем в схеме базы данных. Мы можем просмотреть эти файлы миграций. Они располагаются в директориях<em>migrations</em>внутри приложений. Например, в нашем случае файл миграции располагается в<em>hexlet_django_blog/article/migrations/0001_initial.py</em>.</p>
46
<p><strong>Миграции</strong>- это описания изменений в наших моделях, и в дальнейшем в схеме базы данных. Мы можем просмотреть эти файлы миграций. Они располагаются в директориях<em>migrations</em>внутри приложений. Например, в нашем случае файл миграции располагается в<em>hexlet_django_blog/article/migrations/0001_initial.py</em>.</p>
47
<p>Нам не нужно читать все файлы миграций, когда Django их создает. Но при необходимости мы можем их редактировать, чтобы изменить порядок миграции.</p>
47
<p>Нам не нужно читать все файлы миграций, когда Django их создает. Но при необходимости мы можем их редактировать, чтобы изменить порядок миграции.</p>
48
<p>Теперь посмотрим, какой SQL-запрос будет выполняться при запуске миграции. Для этого воспользуемся командой sqlmigrate:</p>
48
<p>Теперь посмотрим, какой SQL-запрос будет выполняться при запуске миграции. Для этого воспользуемся командой sqlmigrate:</p>
49
<ul><li>Имена таблиц автоматически генерируются с помощью объединения имени приложения (article) и имени модели в нижнем регистре - article</li>
49
<ul><li>Имена таблиц автоматически генерируются с помощью объединения имени приложения (article) и имени модели в нижнем регистре - article</li>
50
<li>Поле id, которое является первичным ключом, добавляется автоматически</li>
50
<li>Поле id, которое является первичным ключом, добавляется автоматически</li>
51
</ul><p>Применяем все остальные миграции. Эта операция<em>идемпотентна</em>:</p>
51
</ul><p>Применяем все остальные миграции. Эта операция<em>идемпотентна</em>:</p>
52
<p>Созданная миграция была применена. Если все прошло успешно, то в базе данных появилась таблица<em>article_article</em>.</p>
52
<p>Созданная миграция была применена. Если все прошло успешно, то в базе данных появилась таблица<em>article_article</em>.</p>
53
<p>В первый раз Django применит приличное количество миграций, которые создают несколько вспомогательных таблиц. Они нужны фреймворку для подсистемы работы с пользователями и прочих вещей, которые входят в обязательный минимум.</p>
53
<p>В первый раз Django применит приличное количество миграций, которые создают несколько вспомогательных таблиц. Они нужны фреймворку для подсистемы работы с пользователями и прочих вещей, которые входят в обязательный минимум.</p>
54
<p>Миграции можно не только накатывать, но и откатывать. Для этого нужно указать версию миграции, к которой мы хотим вернуться.</p>
54
<p>Миграции можно не только накатывать, но и откатывать. Для этого нужно указать версию миграции, к которой мы хотим вернуться.</p>
55
<p>Например, в директории<em>migrations</em>приложения<em>article</em>у нас есть два файла миграции<em>0005_second_last_migration</em>и<em>0006_last_migration</em>. 0006 - это последняя примененная миграция.</p>
55
<p>Например, в директории<em>migrations</em>приложения<em>article</em>у нас есть два файла миграции<em>0005_second_last_migration</em>и<em>0006_last_migration</em>. 0006 - это последняя примененная миграция.</p>
56
<p>Если нам нужно вернуться к миграции 0005 из миграции 0006, мы выполним следующую команду:</p>
56
<p>Если нам нужно вернуться к миграции 0005 из миграции 0006, мы выполним следующую команду:</p>
57
<p>Если нам нужно отменить все миграции этого приложения, нужно указать zero в качестве версии миграции:</p>
57
<p>Если нам нужно отменить все миграции этого приложения, нужно указать zero в качестве версии миграции:</p>
58
<p>Иногда миграция может быть необратимой. Как правило, это возникает, когда в модели вносятся существенные изменения. Когда мы попытаемся вернуться к такой миграции, Django выдаст ошибку IrreversibleError.</p>
58
<p>Иногда миграция может быть необратимой. Как правило, это возникает, когда в модели вносятся существенные изменения. Когда мы попытаемся вернуться к такой миграции, Django выдаст ошибку IrreversibleError.</p>