9.2 KiB
9.2 KiB
status, type, tags, created, updated, source, aliases
| status | type | tags | created | updated | source | aliases | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| processing | concept |
|
2026-05-30 | 2026-05-31 |
|
|
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)