Модели: классы Python как таблицы БД
Модель — это класс Python, который Django превращает в таблицу базы данных. Вы описываете данные один раз на Python, а SQL Django пишет за вас.
Суть: модель = таблица, атрибуты класса = поля = столбцы, экземпляр класса = строка. ORM избавляет от ручного SQL и защищает от инъекций.
Декларативное описание данных
В большинстве веб-приложений данные живут в реляционной базе: таблицы, столбцы, строки. Django позволяет не писать SQL руками. Вместо CREATE TABLE вы объявляете класс, наследник models.Model, а каждое поле описываете как атрибут. Это и есть ORM — Object-Relational Mapping, мост между миром объектов Python и миром таблиц SQL.
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
is_published = models.BooleanField(default=False)
class Meta:
ordering = ["-created_at"]
def __str__(self):
return self.title
Соответствие прямое и наглядное:
Класс Post → таблица blog_post title (CharField) → столбец title VARCHAR(200) body (TextField) → столбец body TEXT created_at → столбец created_at TIMESTAMP is_published → столбец is_published BOOLEAN экземпляр Post(...) → строка таблицы Post.objects.all() → SELECT * FROM blog_post
Типы полей
Поле — это не просто тип данных, а ещё и правила валидации и поведения. Чаще всего используют: CharField (короткая строка, обязателен max_length), TextField (длинный текст), IntegerField, BooleanField, DateTimeField, EmailField, SlugField (URL-дружественная строка), DecimalField (для денег — не используйте FloatField!). У каждого поля есть опции: null (можно ли NULL в базе), blank (можно ли пустое значение в формах), default, unique, choices.
Метод __str__ и класс Meta
Метод __str__ определяет, как объект выглядит в виде строки — в админке, в shell, в логах. Без него вы увидите бесполезное Post object (1). Вложенный класс Meta задаёт метаданные: ordering (сортировка по умолчанию), verbose_name (человекочитаемое имя), indexes (индексы для ускорения запросов), constraints (ограничения целостности на уровне базы).
Как это работает под капотом
Django использует метаклассы: при импорте модели он читает атрибуты-поля и строит внутреннее описание таблицы. На основе этого описания генерируются миграции (об этом — следующий урок) и SQL-запросы. Когда вы пишете Post.objects.filter(is_published=True), Django строит SQL с параметризованными значениями — поэтому ORM по умолчанию защищён от SQL-инъекций.
Поведение choices и валидации легко промоделировать на чистом Python. Вот как выглядит проверка значения по списку допустимых — ровно та логика, что Django применяет к полю с choices:
# Попробуй сам ▶ — валидация choices как в Django-поле
STATUS_CHOICES = [
("draft", "Черновик"),
("review", "На проверке"),
("published", "Опубликовано"),
]
valid = {code for code, _ in STATUS_CHOICES}
def set_status(value):
if value not in valid:
allowed = ", ".join(sorted(valid))
return f"Ошибка: '{value}' недопустимо. Можно: {allowed}"
label = dict(STATUS_CHOICES)[value]
return f"OK: статус = {value} ({label})"
for v in ["draft", "published", "deleted"]:
print(set_status(v))
Денежные значения и точность
Отдельно предупредим про деньги. FloatField хранит число с плавающей точкой, и из-за двоичного представления 0.1 + 0.2 там не равно 0.3. Для цен, балансов и любых финансов используйте DecimalField(max_digits=..., decimal_places=2) — он хранит точное десятичное значение.
Частые ошибки
- Забыть max_length у CharField. Django выдаст ошибку — это обязательный параметр.
- Путать null и blank.
null— про базу,blank— про формы. Для строк обычноnullне ставят, используют пустую строку. - Не определить __str__. Объекты станут нечитаемыми в админке и shell.
- Хранить деньги во FloatField. Будут ошибки округления. Только DecimalField.
Best practices
- Называйте модели в единственном числе и CamelCase:
Post,Order,UserProfile. - Задавайте
orderingв Meta, если данные почти всегда показываются в одном порядке. - Добавляйте
verbose_nameи индексы через Meta для читаемости и скорости. - Используйте
choicesвместо «магических строк» для статусов и типов.
Итоги
Модель — декларативное описание таблицы на Python. Поля — это столбцы с правилами, Meta — метаданные, __str__ — человеческое представление. ORM пишет SQL за вас и защищает от инъекций. Дальше превратим модель в реальную таблицу через миграции.