💻 Примеры: Auth, Permissions, Swagger

Рабочие примеры по темам практикума 10 (Django 6.0, DRF 3.17+)

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

# Авто-привязка request.user
def perform_create(self, serializer):
    serializer.save(customer=self.request.user)

# Кастомное разрешение (owner-only write)
class IsCustomerOrReadOnly(BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in ['GET', 'HEAD', 'OPTIONS']:
            return True
        return obj.customer == request.user

# Проверка пользовательского разрешения
class CanViewStatistics(BasePermission):
    def has_permission(self, request, view):
        return request.user.has_perm('store.can_view_statistics')

Пример 1: Полная цепочка request.user

Создание заказа с авто-привязкой и список заказов только текущего пользователя.

# views.py
from rest_framework import viewsets
from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated
from .models import Order
from .serializers import OrderSerializer

# ViewSet: авто-привязка при создании
class OrderListCreateView(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated]

    def perform_create(self, serializer):
        # customer берётся из запроса, не из данных
        serializer.save(customer=self.request.user)


# Отдельное представление: только заказы текущего пользователя
class UserOrderListView(ListAPIView):
    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return Order.objects.filter(customer=self.request.user)


# urls.py
from django.urls import path
from .views import UserOrderListView, OrderListCreateView

urlpatterns = [
    path('user-orders/', UserOrderListView.as_view(), name='user-orders'),
    path('orders/', OrderListCreateView.as_view({'get': 'list', 'post': 'create'}), name='orders'),
]

Пример 2: Кастомное разрешение IsCustomerOrReadOnly

Объектное разрешение: чтение доступно всем, изменение — только владельцу заказа.

# permissions.py
from rest_framework.permissions import BasePermission

class IsCustomerOrReadOnly(BasePermission):
    """
    Разрешает редактирование объектов только их владельцам (customer),
    остальным — только чтение.
    """
    def has_object_permission(self, request, view, obj):
        # Безопасные методы доступны всем
        if request.method in ['GET', 'HEAD', 'OPTIONS']:
            return True
        # Только владелец может изменять или удалять
        return obj.customer == request.user


# views.py
from rest_framework.generics import RetrieveUpdateDestroyAPIView
from .models import Order
from .serializers import OrderSerializer
from .permissions import IsCustomerOrReadOnly

class OrderDetailUpdateDeleteView(RetrieveUpdateDestroyAPIView):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    permission_classes = [IsCustomerOrReadOnly]

Пример 3: Пользовательское разрешение на уровне модели + эндпоинт статистики

# models.py
from django.db import models

class Order(models.Model):
    order_date = models.DateTimeField(auto_now_add=True)
    customer = models.ForeignKey('Customer', on_delete=models.PROTECT, related_name='orders')

    class Meta:
        permissions = [
            ("can_view_statistics", "Can view statistics"),
        ]


# permissions.py
from rest_framework.permissions import BasePermission

class CanViewStatistics(BasePermission):
    """
    Разрешает доступ к статистике только пользователям с разрешением
    'store.can_view_statistics'.
    """
    def has_permission(self, request, view):
        return request.user.has_perm('store.can_view_statistics')


# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .permissions import CanViewStatistics
from .models import Order

class OrderStatisticsView(APIView):
    permission_classes = [CanViewStatistics]

    def get(self, request, *args, **kwargs):
        total_orders = Order.objects.count()
        data = {'total_orders': total_orders}
        return Response(data)


# urls.py
from .views import OrderStatisticsView

urlpatterns += [
    path('order-statistics/', OrderStatisticsView.as_view(), name='order-statistics'),
]
Не забыть: После добавления Meta.permissions обязательно выполнить:
python manage.py makemigrations
python manage.py migrate
Затем в Admin: создать группу "Statistic" с разрешением "Can view statistics" и присвоить нужному пользователю.

Пример 4: dumpdata / loaddata

# Создать полный дамп
python manage.py dumpdata --indent=4 > db_backup.json

# Восстановление после удаления БД:
# 1. Применить все миграции (создать структуру таблиц)
python manage.py migrate

# 2. Загрузить данные из дампа
python manage.py loaddata db_backup.json

Пример 5: OpenAPI 3 через drf-spectacular

# settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'drf_spectacular',
]

REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

SPECTACULAR_SETTINGS = {
    'TITLE': 'API Documentation',
    'DESCRIPTION': 'API documentation for the project',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
}

# urls.py
from drf_spectacular.views import (
    SpectacularAPIView,
    SpectacularRedocView,
    SpectacularSwaggerView,
)

urlpatterns += [
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]
После запуска сервера документация доступна по адресам:
http://127.0.0.1:8000/api/schema/ — OpenAPI 3 JSON/YAML схема
http://127.0.0.1:8000/api/docs/ — интерактивный Swagger UI
http://127.0.0.1:8000/api/redoc/ — более читаемый ReDoc
← К оглавлению урока    Старый vs Новый →