Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Модели Python: Разработка на фреймворке Django

Django ORM

Практически любое Web-приложение так или иначе работает с базой данных. При этом с системой управления базами данных (СУБД) приложение общается каким-то универсальным способом, например, посредством языка SQL. Однако программисту чаще всего хочется иметь некую абстракцию, позволяющую большую часть времени работать с привычными сущностями языка. Такой абстракцией является Object-Relational Mapping (ORM), отображение сущностей предметной области и их взаимосвязей в объекты, удобные для использования программистом.

Разные ORM по-разному подходят к тому, насколько нужно изолировать пользователя от конкретного хранилища. Есть такие, которые полностью скрывают всю работу с БД, вы пользуетесь объектами, изменяете их состояние, а ORM неявно синхронизирует состояние объектов и сущностей в хранилище. Другие ORM всего лишь оборачивают сущности БД в структуры языка, но все запросы нужно писать вручную. Это два разных полюса, каждый со своими плюсами и минусами. Авторы Django решили остаться где-то посередине.

Используя Django ORM, вы работаете с объектами, и выполняете вручную их загрузку и сохранение, однако используете для этого привычные средства языка — итерацию, вызов методов. Django же берёт на себя обеспечение правильной работы вашего приложения с конкретными хранилищами данных. Эта изоляция от конкретного хранилища позволяет использовать разные БД в разных условиях: при разработке и тестировании использовать что-то более легковесное, а в боевых условиях применять "тяжёлую артиллерию".

Модель

Слово "Модель" часто используется в качестве замены словосочетания "Django ORM", поэтому и в рамках курсов будет использоваться этот термин. Модель в единственном числе говорит нам о том, что наша предметная область смоделирована с помощью средств фреймворка. Это собирательный образ слоя хранения. При этом отдельные сущности тоже называются моделями — модели поменьше собираются в большую Модель всей предметной области.

Связь между моделями и таблицами в БД максимально прямая: одна таблица — одна модель. В этом плане Django ORM не отходит далеко от схемы БД, вы всегда имеете представление, как фактически представлены ваши данные с точки зрения СУБД. Что очень полезно, когда нужно что-то где-то оптимизировать!

Database Engines

К фактической БД Django подключается с помощью Database Engines. Одно приложение может подключаться к нескольким БД, в том числе и с помощью разных "движков". Но такое случается нечасто. Обычно вы будете иметь одну базу на одно Web-приложение.

Описываются БД в словаре settings.DATABASES:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

ENGINE указывает на конкретный движок. NAME в случае SQLite хранит имя файла, для других СУБД это будет имя БД в удобном для них формате. default же является именем БД уже для самого Django. Когда используется несколько баз данных одновременно, эта "умолчательная" используется всегда, когда имя какой-то другой не указано в коде явно.

Описание моделей и генерация миграций

Модели описываются в модулях "models.py", и модели разных приложений обычно в этих приложениях и описываются.

Добавим в hello_django.calc.models следующий код:

from django.db import models


class History(models.Model):
    timestamp = models.DateTimeField(auto_now_add=True)
    value = models.IntegerField()

History — это и есть наша первая модель. Модель имеет два поля (fields): timestamp для хранения даты и времени создания записи и value, которое хранит целое число.

Со стороны Python всё готово. Но нужно ведь сделать так, чтобы соответствующая таблица (помним: одна модель — одна таблица) появилась в базе данных. Для этого нам нужно сгенерировать миграцию (migration).

Миграции меняют схему БД сообразно тому, как мы меняем модель. В Django работа с миграциями сделана на очень высоком уровне. В том числе — на высоком уровне автоматизации!

Чтобы получить миграцию, выполняем команду

python manage.py makemigrations

Migrations for 'calc':
  hello_django/calc/migrations/0001_initial.py
    - Create model History

А теперь применяем все миграции, которые ещё не были применены (эта операция идемпотентна):

python manage.py migrate

Operations to perform:
  ...
Running migrations:
  ...
  Applying calc.0001_initial... OK
  ...

Видим, что созданная миграция была применена.

В первый раз Django применит приличное количество миграций, которые создают несколько вспомогательных таблиц, нужных фреймворку для подсистемы работы с пользователями и прочих вещей, входящих в "обязательный минимум".

Работа с моделью

Запустим специальный вариант REPL, работающий в контексте фреймворка командой python manage.py shell, а в нём импортируем модель и создадим первую запись:

from hello_django.calc.models import History

History(value=42).save()

h = History()
h.value = 100
h.save()

Новый объект модели создаётся инстанциированием класса, но в базу попадает, только когда мы вызываем для экземпляра метод .save(). В созданном, но ещё не сохранённом экземпляре, можно менять любые поля. Поля можно указывать как при конструировании объекта, так и после того, как он создан.

Теперь попробуем запросить данные из БД и вывести значения обоих полей для каждого полученного объекта модели History:

for h in History.objects.all():
    print(h.timestamp, h.value)

# => 2020-04-24 06:55:15.543483+00:00 42
# => 2020-04-24 06:55:53.976316+00:00 100

History.objects — это представление "всех объектов данной модели". В примере выше мы получали действительно все записи, поэтому вызвали .all(), но мы могли бы составить и более сложный запрос. Выведем же "value первой записи, у которой это value больше пятидесяти":

History.objects.filter(value__gt=50).first().value
# 100

Здесь строится целая цепочка вызова методов. И такие цепочки могут быть достаточно длинными. Каждый из шагов уточняет запрос по тому или иному критерию, а в конце всегда стоит вызов какого-то метода, определяющий сколько записей мы хотим получить. В данном случае мы хотим получить одну (первую попавшуюся), поэтому запрос заканчивается вызов метода .first(). А .value мы уже получаем у объекта, являющегося результатом выполнения запроса.

Вы, наверное, обратили внимание на то, как указано условие, по которому выбираются объекты в запросе — value__gt=50. Это так называемый lookup. "value" здесь означает имя поля, а дальше через разделитель "__" (двойное подчёркивание) указывается "gt" — сокращение от "greater than" ("больше чем") и, наконец, само значение.

Такой синтаксис приходится использовать потому, что мы не можем при вызове метода указать аргумент value > 20. Вот авторы и вышли из ситуации, использовав именованные аргументы с такими необычными именами.

ORM — самая большая часть фреймворка

В рамках одного урока невозможно рассказать о том, о чём пишут целые книги. Я попытался дать возможность мельком взглянуть на то, как в Django принято работать с БД, и понять, что это не так уж и сложно. Но подробное изучение Django ORM, конечно же, "потянет" на отдельный курс.

Задание

  • Добавьте описанную выше модель в проект.
  • Сгенерируйте и примените миграцию.
  • Добавьте в hello_django.calc.views.index сохранение каждого вычисленного результата в виде записи в History.
  • Добавьте новую view hello_django.calc.views.history, в которой выводите десять последних результатов вычислений. В шаблоне можете использовать цикл прямо по записям в запросе, так что в контекст шаблона можно поместить сам запрос.

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
1 июня 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»