✅ Решения: ответы на вопросы самопроверки

🎯 Разбор заданий К оглавлению урока

⚡ Краткие ответы

  • __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 шага

  1. Создать класс CustomUser(AbstractBaseUser, PermissionsMixin).
  2. Прописать AUTH_USER_MODEL = 'myapp.CustomUser' в settings.py.
  3. Выполнить makemigrations + migrate.
  4. Зарегистрировать в 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.