🏠 Домашнее задание 17 — Урок 38

← К оглавлению урока

⚡ ДЗ 17 кратко

Задание 1: Глобальная CursorPagination, не более 6 объектов на странице.

Задание 2: Система логирования — консоль (сервер) + logs/http_logs.log (HTTP) + logs/db_logs.log (SQL).

Текст задания из LMS

Python Advanced: Домашнее задание 17

Задание 1

Подумать, какой из видов пагинации более безопасный, чтобы не «светить» явно параметры в запросе. Выбрав нужный класс пагинации подключить глобальную пагинацию в проект. На одной странице должно располагаться не более 6 объектов.

Задание 2

Подключить систему логирования работы включенного сервера в проект для отслеживания логов работы приложения. Логи должны загружаться следующим образом:

  • Отдельно логи работы включенного сервера с выводом в консоль
  • Отдельно логи HTTP запросов и их статусов в отдельную папку logs в корне проекта в файл http_logs.log
  • Отдельно логи запросов в базу данных в отдельную папку logs в корне проекта в файл db_logs.log

Подготовка окружения

Предварительные требования

Убедитесь, что у вас уже есть Django-проект с DRF. Если нет — создайте:

# Создать виртуальное окружение
python -m venv venv
venv\Scripts\activate      # Windows PowerShell
# source venv/bin/activate  # Linux/Mac

# Установить зависимости
pip install django djangorestframework

# Создать проект и приложение
django-admin startproject myproject .
python manage.py startapp first_app
# settings.py — базовая настройка
INSTALLED_APPS = [
    ...
    'rest_framework',
    'first_app',
]

Создать папку logs

# В корне проекта (где manage.py)
mkdir logs
Важно: папку logs/ нужно создать вручную до первого запуска сервера. FileHandler не создаёт директории автоматически.

Git: создать .gitignore

# .gitignore — не коммитить логи
logs/
*.log
*.pyc
__pycache__/
venv/
.env
db.sqlite3

Пошаговое решение — Задание 1: Глобальная пагинация

Шаг 1: Выбор класса пагинации

Задание требует «не светить явно параметры в запросе». Сравниваем три варианта:

КлассПараметры в URLБезопасность
PageNumberPagination ?page=2&page_size=5 Низкая — видны номер и размер
LimitOffsetPagination ?limit=5&offset=10 Средняя — видны смещение и лимит
CursorPagination ?cursor=bz0x... Высокая — курсор зашифрован

Ответ: CursorPagination — курсор зашифрован (base64), клиент не видит реальный offset или номер страницы.

Шаг 2: Создать файл pagination.py

В приложении first_app/ создайте файл pagination.py:

# first_app/pagination.py
from rest_framework.pagination import CursorPagination

class ProjectCursorPagination(CursorPagination):
    page_size = 6              # не более 6 объектов на странице
    ordering = 'created_at'    # укажите поле, которое существует в ваших моделях
Проверьте поле: убедитесь, что поле ordering реально существует в моделях вашего проекта. Если нет поля created_at — укажите другое, например id или title.

Шаг 3: Подключить в settings.py

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'first_app.pagination.ProjectCursorPagination',
    'PAGE_SIZE': 6,
    # ... другие настройки DRF
}

Шаг 4: Проверить в Postman

# Первый запрос
GET http://127.0.0.1:8000/api/books/

# Ожидаемый ответ:
{
    "next": "http://127.0.0.1:8000/api/books/?cursor=bz0xJnA9...",
    "previous": null,
    "results": [/* 6 объектов */]
}

# Следующая страница через cursor из ответа
GET http://127.0.0.1:8000/api/books/?cursor=bz0xJnA9...

Связь с теорией: подробнее о CursorPagination — theory.html#cursor. Примеры — examples.html#global-example.

Пошаговое решение — Задание 2: Система логирования

Шаг 1: Создать структуру папки logs

# В корне проекта (где manage.py):
mkdir logs
# Создаст папку logs/ — FileHandler будет писать туда

Шаг 2: Добавить LOGGING в settings.py

# settings.py
import os

# Убедиться что DEBUG включён для SQL-логов
DEBUG = True

# Путь к папке логов
LOGS_DIR = os.path.join(BASE_DIR, 'logs')
os.makedirs(LOGS_DIR, exist_ok=True)  # создаст если не существует

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,

    'formatters': {
        'verbose': {
            'format': '[{asctime}] {levelname} {name} — {message}',
            'style': '{',
        },
    },

    'handlers': {
        # 1. Консоль — логи включенного сервера
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
        # 2. HTTP-запросы → logs/http_logs.log
        'file_http': {
            'level': 'INFO',
            'class': 'logging.FileHandler',
            'filename': os.path.join(LOGS_DIR, 'http_logs.log'),
            'formatter': 'verbose',
        },
        # 3. SQL-запросы → logs/db_logs.log
        'file_db': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': os.path.join(LOGS_DIR, 'db_logs.log'),
            'formatter': 'verbose',
        },
    },

    'loggers': {
        # Сервер разработки — в консоль
        'django': {
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': True,
        },
        # HTTP-запросы и статусы — в файл
        'django.request': {
            'handlers': ['file_http'],
            'level': 'INFO',
            'propagate': False,
        },
        # SQL-запросы — в файл
        'django.db.backends': {
            'handlers': ['file_db'],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}

Шаг 3: Проверить структуру проекта

После настройки структура должна выглядеть так:

myproject/
├── manage.py
├── myproject/
│   ├── settings.py   ← LOGGING добавлен сюда
│   └── urls.py
├── first_app/
│   ├── pagination.py ← создан на шаге 1 задания 1
│   ├── views.py
│   └── ...
└── logs/             ← папка создана вручную
    ├── http_logs.log ← будет создан при первом HTTP-запросе
    └── db_logs.log   ← будет создан при первом SQL-запросе

Шаг 4: Запустить сервер и проверить

python manage.py runserver

В консоли должны появиться INFO-сообщения Django о запуске сервера.

Проверка в VS Code

Запуск через терминал

  1. Откройте VS Code в папке проекта (File → Open Folder)
  2. Откройте встроенный терминал: Ctrl + ` (или View → Terminal)
  3. Активируйте виртуальное окружение: venv\Scripts\activate
  4. Запустите сервер: python manage.py runserver
  5. Убедитесь, что в терминале видны INFO-логи Django

launch.json — запуск с отладчиком (F5)

Создайте файл .vscode/launch.json для отладки:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Django: runserver",
            "type": "debugpy",
            "request": "launch",
            "program": "${workspaceFolder}/manage.py",
            "args": ["runserver", "--noreload"],
            "django": true,
            "justMyCode": true
        }
    ]
}

Нажмите F5 для запуска сервера в режиме отладки. Теперь можно ставить точки останова прямо в коде Django/DRF.

Точки останова для отладки пагинации

  1. Откройте first_app/pagination.py
  2. Кликните левее строки с page_size = 6 — появится красная точка
  3. Запустите сервер через F5
  4. Сделайте запрос в Postman: GET http://127.0.0.1:8000/api/books/
  5. VS Code остановится на точке останова — можно проверить значения переменных

Проверка файлов логов в VS Code

  1. В проводнике VS Code (левая панель) найдите папку logs/
  2. Откройте http_logs.log — там должны быть строки вида:
    [2024-06-09 12:34:56] INFO django.request — GET /api/books/ 200
  3. Откройте db_logs.log — там должны быть SQL-запросы:
    [2024-06-09 12:34:56] DEBUG django.db.backends — SELECT ... FROM first_app_book ...

Postman: проверка пагинации

  1. Откройте Postman
  2. Создайте GET-запрос: http://127.0.0.1:8000/api/books/
  3. Нажмите Send
  4. В ответе должно быть не более 6 объектов в "results"
  5. Скопируйте значение "next" из ответа
  6. Вставьте как новый запрос и нажмите Send — получите следующую страницу
  7. Убедитесь, что URL содержит ?cursor=..., а не ?page=...