Ответ
Декоратор @action в Django REST Framework (DRF) используется для добавления пользовательских маршрутов (эндпоинтов) к стандартному набору ViewSet.
Стандартный ViewSet предоставляет CRUD-операции (list, create, retrieve, update, destroy). Если требуется дополнительная логика, не вписывающаяся в CRUD, на помощь приходит @action.
Ключевой параметр — detail:
detail=True: Действие применяется к конкретному объекту. URL будет содержатьpkобъекта. Например,POST /users/1/set_password/.detail=False: Действие применяется ко всему набору объектов (коллекции). URL не будет содержатьpk. Например,GET /users/active_users/.
Пример:
Добавим эндпоинт для смены пароля конкретного пользователя и эндпоинт для получения всех активных пользователей.
from django.contrib.auth.models import User
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from .serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# Действие для конкретного объекта (пользователя)
# URL: /users/{pk}/set_password/
@action(detail=True, methods=['post'])
def set_password(self, request, pk=None):
user = self.get_object()
password = request.data.get('password')
if not password:
return Response({'error': 'Password not provided'}, status=status.HTTP_400_BAD_REQUEST)
user.set_password(password)
user.save()
return Response({'status': 'password set'})
# Действие для всей коллекции
# URL: /users/active_users/
@action(detail=False, methods=['get'])
def active_users(self, request):
active_users = User.objects.filter(is_active=True)
serializer = self.get_serializer(active_users, many=True)
return Response(serializer.data)
Основные параметры @action:
detail(bool): Определяет, привязан ли маршрут к объекту или коллекции.methods(list): Список разрешенных HTTP-методов (e.g.,['get', 'post']).url_path(str): Позволяет задать кастомный сегмент URL вместо имени функции.url_name(str): Имя для реверсирования URL (reverse()).