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

108 lines
7.0 KiB
Markdown

---
status: processing
type: concept
tags: [django, backend, orm, database, migrations]
created: 2026-05-30
updated: 2026-05-31
title: "Django: Модели и ORM"
source: ["[[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`: Определение таблиц БД.
## Определение моделей
```python
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` — файл изображения с дополнительной проверкой формата.
### Отношения
- `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, ответственность остаётся на БД и разработчике.
---
## Миграции
Инструмент для синхронизации моделей с БД.
- `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()`.
### Поиск по полям (Field Lookups)
- `exact`, `iexact` (регистронезависимо).
- `gt` (>), `gte` (>=), `lt` (<), `lte` (<=).
- `contains`, `icontains`.
- `in` (список), `range` (диапазон).
- `isnull=True`.
### Оптимизация запросов
- `select_related('field')` — заранее подтягивает связанную запись через `JOIN`. Подходит для `ForeignKey` и `OneToOneField`, когда у объекта есть одна связанная запись.
- `prefetch_related('field')` — делает отдельный запрос за связанными объектами и собирает их в Python. Подходит для `ManyToManyField` и обратных связей, где связанных записей может быть много.
- **Проблема N+1** — ситуация, когда Django делает один запрос за списком объектов, а потом ещё по одному запросу на каждый объект в цикле.
Пример: если вывести 100 книг и для каждой обратиться к `book.author`, без оптимизации может получиться 101 запрос. С `select_related('author')` авторы будут загружены сразу.
### Агрегация и аннотация
- `aggregate(Avg('rating'))` — считает одно итоговое значение по всей выборке: среднее, сумму, минимум, максимум, количество. Возвращает словарь, а не QuerySet.
- `annotate(total=Count('entries'))` — добавляет вычисляемое поле к каждому объекту в выборке.
Пример: `Book.objects.aggregate(Avg('rating'))` вернёт средний рейтинг всех книг. `Author.objects.annotate(total=Count('books'))` добавит каждому автору поле `total` с количеством его книг.
### Логические условия
- `Q-объекты` нужны для сложных условий в `filter()`: `OR` (`|`), `AND` (`&`), `NOT` (`~`).
- `F-выражения` позволяют сравнивать и изменять поля прямо на стороне БД, не загружая значение в Python.
Пример `Q`: найти книги, где рейтинг выше 4 или название содержит `Django`.
Пример `F`: увеличить счётчик просмотров на 1 прямо в БД: `views = F('views') + 1`.