✅ Решения — Урок 26

← К оглавлению урока | ← К заданиям

⚡ Ответы

  • 1.1: 1→B, 2→A, 3→D, 4→C, 5→E
  • 2.1: C — order_by('-field_name')
  • 3.1: B — Subquery
  • 3.2: A — OuterRef
  • 3.3: 1→C, 2→D, 3→A, 4→B
  • 4.1: B — преобразование сложных структур в простые форматы
  • 4.2: C — Модели базы данных (не часть DRF)

Решения — блок «Агрегация»

Задание 1.1 — Сопоставление функций агрегации

Ответ: 1→B, 2→A, 3→D, 4→C, 5→E

  • Count → B (Подсчитывает количество записей)
  • Sum → A (Вычисляет сумму значений)
  • Avg → D (Вычисляет среднее значение)
  • Min → C (Нахождение минимального значения)
  • Max → E (Нахождение максимального значения)

Задание 1.2 — aggregate vs annotate

# Вызов A — возвращает ОДИН словарь для всего QuerySet
result_a = Book.objects.aggregate(total=Count('id'))
# Результат: {'total': 42}  — одно число для всей таблицы

# Вызов B — возвращает QuerySet, где каждый элемент — группа
result_b = Book.objects.values('author').annotate(cnt=Count('id'))
# Результат: [
#   {'author': 1, 'cnt': 5},
#   {'author': 2, 'cnt': 3},
#   ...
# ]  — каждый автор получает свой счётчик

Ключевое отличие: aggregate() возвращает одно итоговое значение; annotate() добавляет поле к каждому объекту/группе.

Решения — блок «order_by и срезы»

Задание 2.1

Ответ: Corder_by('-field_name')

Минус перед именем поля в строке — сортировка по убыванию. Вариант B без кавычек и минуса вызовет NameError.

Задание 2.2 — Срезы

# Места 6–15 по цене (дорогие): отсортировать по убыванию, взять [5:15]
expensive_books = Book.objects.order_by('-price')[5:15]

# Пояснение:
# order_by('-price') — сортировка по убыванию цены
# [5:15]             — пропустить 5 первых, взять следующие 10
# SQL: ORDER BY price DESC LIMIT 10 OFFSET 5

Решения — блок «Подзапросы»

Задание 3.1

Ответ: B — Subquery

Subquery оборачивает QuerySet, делая его подзапросом. OuterRef — для ссылки на внешний запрос, Avg — агрегационная функция.

Задание 3.2

Ответ: A — OuterRef

OuterRef('field') ссылается на значение поля из внешнего (главного) запроса внутри подзапроса. Это позволяет создавать коррелированные подзапросы.

Задание 3.3 — Сопоставление классов

Ответ: 1→C, 2→D, 3→A, 4→B

  • ExpressionWrapper → C (Оборачивает сложные выражения, указывает тип данных)
  • Avg → D (Вычисляет среднее значение поля)
  • Subquery → A (Включает результаты одного QuerySet в другой)
  • OuterRef → B (Ссылается на поля из внешнего запроса)

Решения — блок «DRF»

Задание 4.1

Ответ: B — Процесс преобразования сложных структур данных в простые форматы.

Вариант A — это десериализация (обратный процесс). Вариант C — это валидация.

Задание 4.2

Ответ: C — Модели базы данных.

Модели — это часть Django ORM, а не DRF. DRF работает поверх Django и использует уже готовые модели. Сериализаторы и Views — это компоненты DRF.

Решения — Практические задания

Задание 5.1 — Издательства с более чем 3 книгами

from django.db.models import Count

publishers = Publisher.objects.annotate(
    book_count=Count('book')   # обратная связь через related_name или имя модели в нижнем регистре
).filter(
    book_count__gt=3
).order_by('-book_count')

for pub in publishers:
    print(f"{pub.name}: {pub.book_count} книг")

Пояснение: Count('book') использует обратную связь от Publisher к Book (Django автоматически создаёт связь по имени модели в нижнем регистре). filter(book_count__gt=3) — фильтрация по аннотированному полю.

Задание 5.2 — TaskSerializer

# serializers.py
from rest_framework import serializers
from .models import Task

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = ['id', 'title', 'description', 'status', 'deadline', 'created_at']
        read_only_fields = ['id', 'created_at']

Пояснение:

  • ModelSerializer автоматически создаёт поля из модели
  • fields — явно перечисляем, какие поля включить
  • read_only_fieldsid назначается БД, created_at задаётся auto_now_add=True
  • При создании задачи через POST эти поля игнорируются во входных данных