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

Рабочие примеры по темам практикума 10 (Django 5.x, DRF 3.15+)

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

# Авто-привязка 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: Swagger через drf-yasg

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


# urls.py
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
    openapi.Info(
        title="API Documentation",
        default_version='v1',
        description="API documentation for the project",
        terms_of_service="https://www.google.com/policies/terms/",
        contact=openapi.Contact(email="contact@local.com"),
        license=openapi.License(name="BSD License"),
    ),
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns += [
    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]
После запуска сервера документация доступна по адресам:
http://127.0.0.1:8000/swagger/ — интерактивный Swagger UI
http://127.0.0.1:8000/redoc/ — более читаемый ReDoc
← К оглавлению урока    Старый vs Новый →