✅ Решения: ответы на вопросы самопроверки
⚡ Краткие ответы
- __str__ — строковое представление для admin и Shell. Без него видим
Book object (1). - get() исключения — DoesNotExist (ничего не найдено) и MultipleObjectsReturned (найдено больше одного).
- TabularInline — таблица; StackedInline — вертикальные карточки.
- AUTH_USER_MODEL — прописывается до первой миграции, иначе конфликт с auth-таблицами.
- bulk_create — один SQL INSERT вместо N запросов в цикле.
Блок А: Метод __str__ и класс Meta
A-1. Метод __str__
__str__ определяет строковое представление объекта. Используется в Django Admin (список объектов), Django Shell, логах и сообщениях об ошибках. Без него объекты отображаются как Book object (1) — нечитабельно.
A-2. Класс Meta — атрибуты
| Атрибут | Описание |
|---|---|
db_table | Явное имя таблицы в БД (иначе appname_modelname) |
ordering | Порядок сортировки по умолчанию |
verbose_name | Читаемое имя в admin (ед.ч.) |
unique_together | Уникальность по комбинации полей |
indexes | Список индексов для ускорения запросов |
constraints | Ограничения уровня БД |
get_latest_by | Поле для latest() / earliest() |
A-3. db_table
Django генерирует имя как appname_modelname (всё в нижнем регистре). Изменяется через db_table = 'custom_table_name' в классе Meta.
A-4. index_together vs indexes
index_together объявлен устаревшим в Django 4.2. indexes с models.Index поддерживает именованные индексы, уникальные индексы, частичные индексы и тип индекса (B-tree, Hash и др.).
Блок Б: Административная панель
Б-1. Регистрация модели
Способ 1: admin.site.register(Model, AdminClass). Способ 2: декоратор @admin.register(Model). Рекомендуется декоратор — он лаконичнее и не допускает забыть вызов register.
Б-2. ModelAdmin атрибуты
list_display— поля, отображаемые колонками в списке объектов.search_fields— поля, по которым работает строка поиска.list_filter— боковые фильтры (чекбоксы по уникальным значениям поля).list_per_page— количество объектов на одной странице списка (по умолчанию 100).
Б-3. Action для Task → Done
from django.contrib import admin
from .models import Task
@admin.register(Task)
class TaskAdmin(admin.ModelAdmin):
actions = ['mark_done']
@admin.action(description="Перевести в статус Done")
def mark_done(self, request, queryset):
queryset.update(status='Done')
Блок В: Инлайн-формы
В-1. TabularInline vs StackedInline
TabularInline отображает связанные объекты как строки таблицы — компактно. StackedInline — вертикально карточками, каждый объект занимает больше места. Используйте TabularInline, если полей мало; StackedInline — если объект сложный и читаемость важнее компактности.
В-2. extra
extra = 1 означает, что на странице редактирования основной модели будет показана 1 пустая инлайн-форма для создания нового связанного объекта.
В-3. SubTask inline для Task
from django.contrib import admin
from .models import Task, SubTask
class SubTaskInline(admin.TabularInline):
model = SubTask
extra = 1
fields = ('title', 'status', 'deadline')
@admin.register(Task)
class TaskAdmin(admin.ModelAdmin):
list_display = ('title', 'status', 'deadline')
inlines = [SubTaskInline]
Блок Г: Модель User
Г-1. Поля User
Обязательные: username, password. Необязательные: email, first_name, last_name. Системные: is_staff (False), is_active (True), is_superuser (False), last_login (null), date_joined (текущее время).
Г-2. Иерархия User
- AbstractBaseUser — password, last_login; set_password(), check_password().
- PermissionsMixin — is_superuser, groups, user_permissions; has_perm(), has_module_perms().
- AbstractUser — username, email, first_name, last_name, is_staff, date_joined.
- User — конечный класс, используемый по умолчанию.
Г-3. Кастомный User — 4 шага
- Создать класс
CustomUser(AbstractBaseUser, PermissionsMixin). - Прописать
AUTH_USER_MODEL = 'myapp.CustomUser'в settings.py. - Выполнить
makemigrations+migrate. - Зарегистрировать в admin через
CustomUserAdmin(BaseUserAdmin).
Важно: AUTH_USER_MODEL нужно прописать ДО первой миграции. После применения миграций изменить модель User крайне сложно — это вызывает конфликты в таблицах auth и сессий.
Блок Д: ORM-запросы
Д-1. QuerySet и ленивость
QuerySet — объект, описывающий запрос к БД. Он «ленивый» (lazy): реальный SQL не выполняется до итерации, среза или вызова методов типа count() / exists(). Это позволяет строить сложные запросы цепочкой методов без промежуточных обращений к БД.
Д-2. get() vs filter()
get() возвращает ровно одну запись. При нулевом результате — DoesNotExist, при нескольких — MultipleObjectsReturned. filter() всегда возвращает QuerySet (пустой при отсутствии совпадений).
Д-3. Lookups
# содержит "Great" без учёта регистра
books = Book.objects.filter(title__icontains="great")
# опубликованы в 2010–2023
books = Book.objects.filter(published_date__range=["2010-01-01", "2023-12-31"])
# без указанной цены
books = Book.objects.filter(price__isnull=True)
Д-4. Класс Q — комбинированный запрос
from django.db.models import Q
books = Book.objects.filter(
(Q(is_bestseller=True) | Q(published_date__gt="2000-01-01"))
& ~Q(author="George Orwell")
)
Д-5. Класс F — увеличить цену на 15%
from django.db.models import F
Book.objects.update(price=F('price') * 1.15)
F позволяет ссылаться на значение поля в БД напрямую — без загрузки объектов в Python. Это атомарно и в разы эффективнее при массовых операциях.
Д-6. Bulk-операции
Обычный цикл с save() выполняет N отдельных INSERT-запросов. bulk_create — один запрос INSERT для всего списка. Предпочтительно при создании десятков и более объектов. Ограничение: не вызываются сигналы pre_save/post_save, не присваивается id при некоторых бэкендах без update_conflicts.