💻 Примеры — Урок 38

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

⚡ Ключевые примеры

# pagination_class в представлении
class BookListView(ListAPIView):
    pagination_class = BookPagination  # ваш класс

# Глобально в settings.py
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
}

# LOGGING в settings.py
LOGGING = {
    'version': 1, 'disable_existing_loggers': False,
    'handlers': {'console': {'class': 'logging.StreamHandler'}},
    'loggers': {'django.db.backends': {'handlers': ['console'], 'level': 'DEBUG'}},
}

Пример 1: Book API с PageNumberPagination

# models.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()
    price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    is_bestseller = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title
# serializers.py
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'
# views.py — PageNumberPagination
from rest_framework.generics import ListAPIView
from rest_framework.pagination import PageNumberPagination
from .models import Book
from .serializers import BookSerializer

class BookPagination(PageNumberPagination):
    page_size = 5
    page_size_query_param = 'page_size'
    max_page_size = 100

class BookListView(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = BookPagination

Запросы и ответ PageNumberPagination

GET http://127.0.0.1:8000/books/        # первая страница, 5 элементов
GET http://127.0.0.1:8000/books/?page=2  # вторая страница
GET http://127.0.0.1:8000/books/?page=2&page_size=3  # вторая страница, 3 элемента
{
    "count": 22,
    "next": "http://127.0.0.1:8000/books/?page=2",
    "previous": null,
    "results": [
        {"id": 1, "title": "The Great Gatsby", "author": "F. Scott Fitzgerald", ...},
        {"id": 2, "title": "1984", "author": "George Orwell", ...},
        ...
    ]
}

Пример 2: Book API с LimitOffsetPagination

# views.py — LimitOffsetPagination
from rest_framework.generics import ListAPIView
from rest_framework.pagination import LimitOffsetPagination
from .models import Book
from .serializers import BookSerializer

class BookListLimitView(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = LimitOffsetPagination
# Получить 5 книг, начиная с позиции 10
GET http://127.0.0.1:8000/books/?limit=5&offset=10
{
    "count": 22,
    "next": "http://127.0.0.1:8000/books/?limit=5&offset=15",
    "previous": "http://127.0.0.1:8000/books/?limit=5&offset=5",
    "results": [...]
}

Пример 3: Book API с CursorPagination

# views.py — CursorPagination
from rest_framework.generics import ListAPIView
from rest_framework.pagination import CursorPagination
from .models import Book
from .serializers import BookSerializer

class BookCursorPagination(CursorPagination):
    page_size = 5
    ordering = 'published_date'  # поле существует в модели

class BookListCursorView(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = BookCursorPagination
# Первая страница
GET http://127.0.0.1:8000/books/
{
    "next": "http://127.0.0.1:8000/books/?cursor=bz0xJnA9MjAyMS0wMS0wMQ%3D%3D",
    "previous": null,
    "results": [
        {
            "id": 22,
            "title": "The Great Gatsby",
            "author": "F. Scott Fitzgerald",
            "published_date": "1925-04-10",
            "price": "10.23",
            "is_bestseller": false
        },
        ...
    ]
}
# Следующая страница через курсор
GET http://127.0.0.1:8000/books/?cursor=bz0xJnA9MjAyMS0wMS0wMQ%3D%3D

Пример 4: Глобальная настройка + кастомный CursorPagination

# pagination.py (в приложении first_app)
from rest_framework.pagination import CursorPagination

class CustomCursorPagination(CursorPagination):
    page_size = 6              # не более 6 объектов на странице (ДЗ 17)
    ordering = 'published_date'
# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'first_app.pagination.CustomCursorPagination',
    'PAGE_SIZE': 6,
}
# views.py — пагинация применяется автоматически
from rest_framework.generics import ListAPIView
from .models import Book
from .serializers import BookSerializer

class BookListView(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # pagination_class НЕ указываем — берётся из глобальных настроек

Пример 5: LOGGING для SQL-запросов

# settings.py — полная конфигурация логирования
import os

DEBUG = True  # обязательно для django.db.backends

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': os.path.join(BASE_DIR, 'db.log'),
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console', 'file'],
            'level': 'DEBUG',
        },
    },
}

Что появится в консоли при запросе

(0.002) SELECT "first_app_book"."id",
               "first_app_book"."title",
               "first_app_book"."author",
               "first_app_book"."published_date",
               "first_app_book"."price",
               "first_app_book"."is_bestseller",
               "first_app_book"."created_at"
          FROM "first_app_book"
         ORDER BY "first_app_book"."published_date" ASC
         LIMIT 6; args=()

Пример 6: Расширенное логирование (сервер + HTTP + SQL)

Полная конфигурация согласно ДЗ 17: три потока логов — консоль, HTTP-файл, SQL-файл.

# settings.py
import os

BASE_DIR = ...  # уже определён выше в settings.py
LOGS_DIR = os.path.join(BASE_DIR, 'logs')

# Создать папку logs автоматически при старте (опционально)
os.makedirs(LOGS_DIR, exist_ok=True)

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '[{asctime}] {levelname} {name} — {message}',
            'style': '{',
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
        'file_http': {
            'level': 'INFO',
            'class': 'logging.FileHandler',
            'filename': os.path.join(LOGS_DIR, 'http_logs.log'),
            'formatter': 'verbose',
        },
        '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,
        },
        'django.request': {
            'handlers': ['file_http'], # HTTP-запросы → http_logs.log
            'level': 'INFO',
            'propagate': False,
        },
        'django.db.backends': {
            'handlers': ['file_db'],   # SQL-запросы → db_logs.log
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}
Важно: создайте папку logs/ вручную или через os.makedirs(LOGS_DIR, exist_ok=True) до первого запуска. FileHandler не создаёт директории автоматически — при отсутствии папки сервер упадёт с FileNotFoundError.