Django ModelViewSet возвращает полную ошибку HTML 500 при дублировании поля, установленного в unique=true

Я пытаюсь исправить это все утро, но, похоже, не могу найти проблему. У меня есть конкретный API, возвращающий ошибку IntegrityError дублирующего ключа в виде трассировки ошибки Django HTML вместо того, чтобы возвращать детальную ошибку (JSON) на поле формы.

Тип исключения: IntegrityError at /api/chats/ Значение исключения: дублирующее значение ключа нарушает уникальное ограничение "chats_chat_title_853c3234_uniq" ПОДРОБНАЯ ИНФОРМАЦИЯ: Ключ (title)=(Новый чат) уже существует.

Модель с полем заголовка, установленным на уникальность:

class Chat(TimestampedModel):
    """
    A chat between multiple users.
    """
    uuid = models.UUIDField(default=uuid4, null=False)
    title = models.CharField(
        max_length=255, null=False, unique=True, blank=False)

Сериализатор для чата:

class ChatSerializer(serializers.ModelSerializer):
    title = serializers.CharField(max_length=255)

    def create(self, validated_data):
        """
        Creates a new Chat and adds the m2m employees to it
        """
        user = self.context['request'].user
        title = validated_data['title']

        # Add the user to the chat
        employee_ids = validated_data.pop("employee_ids")
        employee_ids.append(user.id)

        # Create and save the chat
        # Add the employees to the chat
        # Add the sender to the chat
        chat = Chat.objects.create(created_by=user, title=title)
        chat.employees.set(employee_ids)
        chat.employees.add(user)
        chat.save()
        return chat

И ViewSet:

class ChatViewSet(MixedPermissionModelViewSet):
    lookup_field = 'uuid'
    queryset = Chat.objects.all()
    serializer_class = ChatSerializer
    permission_classes_by_action = {
        'list': [IsAuthenticated],
        'create': [IsAuthenticated],
        'update': [IsAuthenticated],
        'retrieve': [IsAuthenticated],
        'partial_update': [IsAuthenticated],
        'destroy': [IsAuthenticated]
    }

    def add_user_has_viewed(self, chat):
        if self.request.user in chat.employees.all():
            chat.has_viewed.add(self.request.user)
            chat.save()
        return chat

    def perform_create(self, serializer):
        chat = serializer.save()
        self.add_user_has_viewed(chat)

Это специфично для данного API при создании объекта. Что я упускаю?

Вероятно, это происходит потому, что исключение IntegrityError возникает на уровне ORM и не обрабатывается стандартным обработчиком исключений Django Rest Framework. Лучший способ исправить это, не переписывая внутренности ViewSet - определить пользовательский обработчик исключений, как описано здесь .

from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status
from django.db import IntegrityError


def integrity_error_exception_handler(exc, context):
    response = exception_handler(exc, context)

    if isinstance(exc, IntegrityError) and not response:
        response = Response({'detail': 'Your error message'}, status=status.HTTP_400_BAD_REQUEST)

    return response

Затем добавьте этот обработчик в settings.py

REST_FRAMEWORK = {
...
'EXCEPTION_HANDLER': 'utils.exceptions.integrity_error_exception_handler'
}

Кроме того, вы можете использовать параметры exc и context для доступа к исходному исключению и объекту представления, чтобы возвращать более общие ответы.

Вернуться на верх