12 KiB
status, type, tags, created, updated, source, aliases
| status | type | tags | created | updated | source | aliases | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| processing | concept |
|
2026-05-30 | 2026-06-05 |
|
|
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)
Если не указать primary_key=True, Django автоматически создаёт поле id. В современных версиях тип поля по умолчанию обычно задаётся настройкой DEFAULT_AUTO_FIELD, часто это BigAutoField.
CharField требует max_length, потому что БД должна знать максимальный размер строки.
null=True и blank=True — не одно и то же:
null=Trueразрешает хранитьNULLв базе данных;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)
related_name задаёт имя обратной связи. Если у книги есть author = ForeignKey(Author, related_name="books"), то у автора можно получить книги так:
author.books.all()
Для ManyToManyField промежуточная модель задаётся через through, когда у самой связи есть дополнительные поля:
class Student(models.Model):
name = models.CharField(max_length=100)
class Course(models.Model):
title = models.CharField(max_length=100)
students = models.ManyToManyField(Student, through="Enrollment")
class Enrollment(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
grade = models.IntegerField(null=True, blank=True)
Связь можно менять методами .add(), .remove(), .set(), .clear().
Миграции
Инструмент для синхронизации моделей с БД.
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)
Простыми словами для экзамена
Модель Django — это Python-класс, который описывает таблицу БД. Поле модели — это колонка таблицы. Объект модели — это строка таблицы.
Class Meta задаёт служебные настройки модели: сортировку, человекочитаемые имена, ограничения, имя таблицы.
Основные методы QuerySet:
.all()— все объекты;.filter()— несколько объектов по условию;.exclude()— всё, кроме условия;.get()— ровно один объект; если ноль или больше одного, будет ошибка;.order_by()— сортировка;.count()— количество;.exists()— есть ли хотя бы одна запись;.distinct()— убрать дубли;.aggregate()— один итог по всей выборке, возвращает словарь;.annotate()— добавляет вычисляемое поле каждому объекту.
Если нужно найти максимум цены по каждой категории, используют annotate() на категориях:
Category.objects.annotate(max_price=Max("product__price"))
Если нужен один максимум по всем товарам, используют aggregate():
Product.objects.aggregate(max_price=Max("price"))