HTML Diff
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>