Модели Django и ORM
Модели, миграции, QuerySet
Модель — это таблица, описанная классом
В Django не нужно писать SQL для создания таблиц. Вы описываете класс, фреймворк сам генерирует схему и умеет с ней работать. Ниже — модель статьи блога:
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
body = models.TextField()
is_published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
Метод __str__ не обязателен, но без него в админке вместо названий будет «Post object (1)».
Основные типы полей
- CharField — строка фиксированной длины, обязателен
max_length. - TextField — длинный текст без ограничения.
- BooleanField — да или нет, удобно для публикации.
- DateTimeField — дата и время;
auto_now_addставит дату при создании. - ForeignKey — связь «много к одному»: у статьи один автор.
- DecimalField — деньги; для цен забудьте про Float, он теряет копейки.
Миграции
Любое изменение моделей фиксируется миграцией — это версионирование схемы базы. Две команды, которые нужны каждый раз: makemigrations создаёт файл с изменениями, migrate применяет его к базе. Файлы миграций хранятся в репозитории: по ним другой разработчик или сервер соберёт такую же схему.
Запросы через ORM
ORM заменяет SQL конструкциями Python. Базовые операции:
Post.objects.create(title="Первый пост", slug="first", body="Текст")
Post.objects.filter(is_published=True).order_by("-created_at")
Post.objects.get(slug="first")
Post.objects.exclude(title__icontains="тест")
Post.objects.filter(is_published=True).count()
Двойное подчёркивание отделяет поле от операции: title__icontains, views__gte, status__in, deleted_at__isnull.
F и Q. Для сравнения полей между собой и для сложных условий:
from django.db.models import F, Q
Post.objects.filter(views__gt=F("likes"))
Post.objects.filter(Q(is_published=True) | Q(is_featured=True))
select_related. Если выводите 20 статей и у каждой обращаетесь к автору, Django сделает 21 запрос к базе. Это проблема N+1, и решается она так: Post.objects.select_related("author") — один запрос вместо двадцати одного. Для связей «многие ко многим» есть prefetch_related.
Частые ошибки
- Править схему вручную. Изменение таблицы в обход миграций приводит к тому, что миграции перестают видеть расхождения.
- Использовать get для поиска в списке. Он падает с ошибкой, если записей ноль или больше одной. Для списков —
filter. - Забыть про индексы. Поле, по которому часто ищут, должно иметь
db_index=True. - Тянуть всё в память. Выборка на 100 000 записей съест гигабайт. Для перебора —
iterator(), для списков — пагинация.
Нужен сайт на Django, а не статья?
Сделаю проект под ключ: модели данных, админка, интеграции с 1С и оплатой, REST API, деплой на ваш сервер с HTTPS и резервными копиями. С 2009 года, по договору, с поддержкой после запуска.
Полезно по теме: установка Django, views и URL, деплой на VPS, обзор Django.