Files
SecondBrain/90 Library/Programming/Python/Django: Модели и ORM.md
T
2026-05-31 10:08:46 +03:00

9.2 KiB

status, type, tags, created, updated, title, source
status type tags created updated title source
processing concept
django
backend
orm
database
migrations
2026-05-30 2026-05-31 Django Модели и ORM
lec1-django_start_models-1.pdf
lec4-django_lec_queries.pdf
p1-django-1.pdf

Django Модели и ORM

Django ORM (Object-Relational Mapping) — технология связи объектно-ориентированного кода и реляционной БД. Реализует паттерн Active Record.

Структура проекта

  • manage.py: Утилита командной строки.
  • settings.py: Конфигурация проекта (БД, INSTALLED_APPS).
  • urls.py: Описание маршрутов.
  • models.py: Определение таблиц БД.
project/
├── manage.py
├── project/
│   ├── settings.py
│   └── urls.py
└── app/
    └── models.py

Определение моделей

from django.db import models

class Person(models.Model):
    first_name = models.CharField("Имя", max_length=30)
    age = models.IntegerField(default=18)
    bio = models.TextField(blank=True)
    
    class Meta:
        verbose_name = "Человек"
        ordering = ["-first_name"]

Типы полей

  • AutoField — автоинкрементный числовой первичный ключ.
  • CharField(max_length=N) — короткая строка фиксированной максимальной длины.
  • TextField — длинный текст без обязательного ограничения длины.
  • IntegerField — целое число.
  • DecimalField(max_digits, decimal_places) — точное десятичное число, удобно для денег и измерений.
  • BooleanField — логическое значение True/False.
  • DateField — дата без времени.
  • DateTimeField — дата и время.
  • EmailField — строка с валидацией email-адреса.
  • FileField — путь к загруженному файлу.
  • ImageField — файл изображения с дополнительной проверкой формата.
class Article(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=200)
    body = models.TextField()
    views = models.IntegerField(default=0)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    is_published = models.BooleanField(default=False)
    published_at = models.DateTimeField(null=True, blank=True)
    author_email = models.EmailField()
    attachment = models.FileField(upload_to="files/", blank=True)
    cover = models.ImageField(upload_to="covers/", blank=True)

Отношения

  • ForeignKey(Target, on_delete=...) — связь "один ко многим": у одной записи Target может быть много связанных записей текущей модели.
  • OneToOneField(Target, on_delete=...) — связь "один к одному": каждой записи соответствует максимум одна связанная запись.
  • ManyToManyField(Target) — связь "многие ко многим": записи обеих моделей могут ссылаться на несколько записей другой модели.

on_delete задаёт, что делать с текущей записью, если удаляется связанная запись Target:

  • CASCADE — удалить текущую запись вместе со связанной.
  • PROTECT — запретить удаление связанной записи, пока на неё есть ссылки.
  • SET_NULL — записать NULL в поле связи; требует null=True.
  • SET_DEFAULT — записать значение по умолчанию; требует default.
  • DO_NOTHING — ничего не делать на уровне Django, ответственность остаётся на БД и разработчике.
class Author(models.Model):
    name = models.CharField(max_length=100)


class Profile(models.Model):
    author = models.OneToOneField(Author, on_delete=models.CASCADE)
    bio = models.TextField()


class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.PROTECT)
    co_authors = models.ManyToManyField(Author, related_name="coauthored_books", blank=True)

Миграции

Инструмент для синхронизации моделей с БД.

  • python manage.py makemigrations — создать файлы миграций.
  • python manage.py migrate — применить изменения в БД.
  • python manage.py showmigrations — список статусов миграций.

Работа с QuerySet (Запросы)

Django QuerySet ленивы (вычисляются только при обращении) и поддерживают цепочки методов.

Базовые CRUD операции

  • Create: obj = Person.objects.create(name="Ivan") или obj.save().
  • Read:
    • Person.objects.all() (все),
    • Person.objects.get(id=1) (один),
    • Person.objects.filter(age__gt=20) (фильтрация).
  • Update: Person.objects.filter(id=1).update(age=25).
  • Delete: obj.delete() или QuerySet.delete().
# Create
person = Person.objects.create(first_name="Ivan", age=25)

# Read
people = Person.objects.all()
person = Person.objects.get(id=1)
adults = Person.objects.filter(age__gte=18)

# Update
Person.objects.filter(id=1).update(age=26)

# Delete
person.delete()

Поиск по полям (Field Lookups)

  • exact, iexact (регистронезависимо).
  • gt (>), gte (>=), lt (<), lte (<=).
  • contains, icontains.
  • in (список), range (диапазон).
  • isnull=True.
Person.objects.filter(first_name__exact="Ivan")
Person.objects.filter(first_name__iexact="ivan")
Person.objects.filter(age__gt=18)
Person.objects.filter(age__range=(18, 30))
Person.objects.filter(first_name__icontains="iv")
Person.objects.filter(id__in=[1, 2, 3])
Person.objects.filter(bio__isnull=True)

Оптимизация запросов

  • select_related('field') — заранее подтягивает связанную запись через JOIN. Подходит для ForeignKey и OneToOneField, когда у объекта есть одна связанная запись.
  • prefetch_related('field') — делает отдельный запрос за связанными объектами и собирает их в Python. Подходит для ManyToManyField и обратных связей, где связанных записей может быть много.
  • Проблема N+1 — ситуация, когда Django делает один запрос за списком объектов, а потом ещё по одному запросу на каждый объект в цикле.
# select_related: книга + её автор загружаются одним SQL-запросом
books = Book.objects.select_related("author")

for book in books:
    print(book.title, book.author.name)
# prefetch_related: авторы загружаются отдельно, затем Django связывает их с книгами
books = Book.objects.prefetch_related("authors")

for book in books:
    print(book.title, [author.name for author in book.authors.all()])

Агрегация и аннотация

  • aggregate(Avg('rating')) — считает одно итоговое значение по всей выборке: среднее, сумму, минимум, максимум, количество. Возвращает словарь, а не QuerySet.
  • annotate(total=Count('entries')) — добавляет вычисляемое поле к каждому объекту в выборке.
from django.db.models import Avg, Count

# aggregate: одно итоговое значение по всей таблице книг
result = Book.objects.aggregate(avg_rating=Avg("rating"))
print(result["avg_rating"])

# annotate: вычисляемое поле для каждого автора
authors = Author.objects.annotate(total_books=Count("books"))

for author in authors:
    print(author.name, author.total_books)

Логические условия

  • Q-объекты нужны для сложных условий в filter(): OR (|), AND (&), NOT (~).
  • F-выражения позволяют сравнивать и изменять поля прямо на стороне БД, не загружая значение в Python.
from django.db.models import F, Q

# Q: рейтинг выше 4 или название содержит Django
books = Book.objects.filter(
    Q(rating__gt=4) | Q(title__icontains="Django")
)

# F: увеличить счётчик просмотров прямо в БД
Book.objects.filter(id=1).update(views=F("views") + 1)