Тема 4 из 6

Модели и запросы

Главная сила Django — ORM: таблицы базы данных описываются классами Python, а запросы пишутся методами, без SQL.

Модель

from django.db import models


class Post(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField(blank=True)
    created = models.DateField()
    views = models.PositiveIntegerField(default=0)
    published = models.BooleanField(default=True)

Каждый класс — таблица, каждое поле — столбец. Поле id Django добавляет само. Типы полей: CharField (строка с ограничением длины), TextField, IntegerField, BooleanField, DateField, DateTimeField и другие.

В обычном проекте модели лежат в models.py приложения, а таблицы создают миграции: python manage.py makemigrations и python manage.py migrate. В задачах курса проект в одном файле, поэтому у модели указано app_label, а таблица создаётся прямо в программе:

with connection.schema_editor() as editor:
    editor.create_model(Post)

База — файл SQLite во временной папке: при каждом запуске она новая.

Создание и чтение

p = Post.objects.create(title="Привет, мир", created=date(2026, 10, 1))
p.views += 1
p.save()

Post.objects.all()                       # все
Post.objects.get(pk=1)                    # один (или исключение DoesNotExist)
Post.objects.count()

Фильтры и порядок

Post.objects.filter(published=True)                # где published = True
Post.objects.exclude(published=False)              # кроме
Post.objects.filter(views__gte=100)                # views >= 100
Post.objects.filter(created__year=2026)            # по году даты
Post.objects.filter(title__startswith="Как")
Post.objects.order_by("-created", "-id")          # по убыванию даты, потом id
Post.objects.filter(...).order_by(...)[:5]         # первые 5 (LIMIT)
  • методы возвращают QuerySet — его можно уточнять цепочкой, а запрос в базу уйдёт, только когда вы начнёте перебирать результат;
  • двойное подчёркивание — поиск (lookup): gt, gte, lt, lte, in, contains, icontains, startswith, year, month…;
  • минус в order_by — обратный порядок; второе поле решает ничьи. Без явного порядка база может вернуть записи в любом порядке.

Поиск без учёта регистра icontains в SQLite работает только для латиницы. В PostgreSQL — для любых букв.

Группировка

from django.db.models import Count, Sum, Avg

Post.objects.aggregate(total=Sum("views"))                       # {'total': 1520}
Post.objects.values("author").annotate(n=Count("id"))            # по авторам

aggregate считает одно значение по всем записям, а values(...).annotate(...) — значение для каждой группы, как GROUP BY в SQL. Результат — словари.

Итог

  • models.Model, поля, objects.create, save;
  • filter, exclude, order_by("-поле"), срезы;
  • поиски __gte, __year, __startswith;
  • aggregate, values(...).annotate(Count, Sum).