Django ORM
Django-проект должен хранить массу данных: посты пользователей, информацию о самих пользователях, большое количество технической информации. Пора организовать взаимодействие кода проекта и базы данных.
Классы описывают новые типы объектов и позволяют создавать экземпляры таких объектов.
Записи в базах данных тоже описывают объекты — наборы свойств, которыми можно управлять. Вы уже пережили множество прекрасных мгновений, работая со SQL-запросами.
Есть способ связать данные объектов с записями в БД, упростить и автоматизировать стандартные операции, и при этом обойтись без запросов на SQL.
Это делает Django ORM — Object-Relational Mapping, «объектно-реляционное отображение». Object — объекты, которые созданы на основе классов, relational — реляционные базы данных, а mapping — связь между системой объектов и базами данных.
Django ORM — это инструмент для работы с данными реляционной БД посредством классов, которые создаёт сам программист. Реализаций ORM существует много, работать мы будем с ORM, встроенной в Django.
Вот класс, описывающий данные для нашего проекта Yatube:
Скопировать код
Класс: Post
Свойства:
- Текст публикации
- Дата публикации
- Автор
Скопировать кодPYTHON
class Post:
def __init__(self, text, pub_date, author):
self.text = text
self.pub_date = pub_date
self.author = author
Классы, с которыми работает ORM, называются модели. Для них в Django есть специальный синтаксис.
Скопировать кодPYTHON
class Post(models.Model):
text = models.TextField()
pub_date = models.DateTimeField("date published", auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
Для всех моделей Django ORM создаст в БД таблицы.
Описанные через синтаксис имя_свойства = models.тип_данных() свойства модели определят названия и типы данных в колонках таблицы БД.
Так, для модели Post в базе данных будет создана таблица с колонками text, pub_date и author, причём в колонке author должны быть указаны Primary Key записей из таблицы User.
Магия здесь в том, что после создания модели Django автоматически проведёт массу операций:
- Создаст необходимые таблицы в базе данных
- Добавит первичный ключ (primary key), по которому можно будет обратиться к нужной записи
- Добавит интерфейс администратора
- Создаст формы для добавления и редактирования записей в таблице
- Настроит проверку данных, введенных в веб-формы
- Предоставит возможность изменения таблиц в БД (миграций, о них позже)
- Создаст SQL запросы для создания таблицы, поиска, изменения, удаления данных, настроит связи между данными, обеспечив их целостность
- Предоставит специальный синтаксис формирования запросов
- Добавит необходимые индексы в базу данных для ускорения работы сайта
Впечатляющий список.
Подробный взгляд на модель
Модель, соответствующая нашей задаче, полностью выглядит так:
Скопировать кодPYTHON
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Post(models.Model):
text = models.TextField()
pub_date = models.DateTimeField("date published", auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
Первые строки импортируют нужные модули.
Всё, что относится к моделям, импортируется из модуля db в классе models
Скопировать кодPYTHON
from django.db import models
from django.contrib.auth import get_user_model
В проекте
Yatube мы дадим пользователям возможность регистрироваться и создавать свои страницы, и нам нужен инструмент для создания и администрирования аккаунтов. В Django встроена работа с пользователями. Для управления ими создана специальная модель
User, и мы импортируем её. Официальная
документация рекомендует обращаться к модели User через функцию
get_user_model. Следуем этой рекомендации:
Скопировать кодPYTHON
User = get_user_model()
Описание модели начинается с объявления: класс Post — это наследник класса Model из модуля models.
Класс Model нужен для того, чтобы от него наследовались модели, классы, обрабатывающие данные. У класса Model есть множество предустановленных свойств и методов, обеспечивающих работу с БД.
Свойства модели связаны со столбцами таблицы в БД, а методы превращаются в запросы.
Скопировать кодPYTHON
class Post(models.Model):
text = models.TextField()
pub_date = models.DateTimeField("date published", auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
Для свойств моделей указывают типы данных, соответствующие типам данных в БД.
В коде модели Post мы применили:
- TextField — поле для хранения произвольного текста;
- DateTimeField — поле для хранения даты и времени. Существуют похожие типы: для хранения даты DateField, промежутка времени DurationField, и просто времени TimeField;
- ForeignKey — поле, в котором указывается ссылка на другую модель, или, в терминологии баз данных, ссылка на другую таблицу, на её Primary Key (pk). В нашем случае это ссылка на модель User. Это свойство обеспечивает связь (relation) между таблицами баз данных.
Параметр on_delete=models.CASCADE обеспечивает связность данных: если из таблицы User будет удалён пользователь, то будут удалены все связанные с ним посты.
Другие популярные типы полей:
- BooleanField — поле для хранения данных типа bool;
- EmailField — поле для хранения строки, но с обязательной проверкой синтаксиса email;
- FileField — поле для хранения файлов. Есть сходный, но более специализированный тип ImageField, предназначенный для хранения файлов картинок.
В Django ORM есть и другие типы полей.
Документация даёт полное описание базовых полей, но есть расширения, добавляющие новые типы полей или переопределяющие базовые типы.
Добавление модели в проект
Время кодить.
Разместим код модели Post в проекте. В Django код моделей хранят в файлах models.py. Обычно такой файл создают в каждом приложении (app) проекта.
Вы создали приложение Posts, в его директории появился файл posts/models.py. По умолчанию в этом файле прописан только импорт модуля models:
Скопировать кодPYTHON
from django.db import models
Добавьте в файл код модели Post. Теперь models.py должен выглядеть так:
Скопировать кодPYTHON
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Post(models.Model):
text = models.TextField()
pub_date = models.DateTimeField("date published", auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
Обратите внимание на поле author. Оно ссылается на автора поста, на модель User, и для этого поля указано свойство related_name="posts".
Тут снова начинается магия: в каждом объекте модели User автоматически будет создано свойство с таким же названием (posts), и в нём будут храниться ссылки на все объекты модели Post, которые ссылаются на объект User.
На практике это означает, что в объекте записи есть поле author, в котором хранится ссылка на автора(например, admin), а в объекте пользователя admin появилось поле posts, в котором хранятся ссылки на все посты этого автора. И теперь можно получить список постов автора, обратившись к его свойству posts
В следующем уроке вы добавите модель в базу данных проекта.