I have been trying to fix this all morning but can't seem to find the issue. I have a specific API returning an IntegrityError
duplicate key error in the form of the Django HTML error traceback instead of returning a detail error (JSON) on the form field.
I expect an error response to be in JSON form such that I can update the form using error.response.data
but instead it is returning the classic Django error page with this snippet:
Exception Type: IntegrityError at /api/chats/ Exception Value: duplicate key value violates unique constraint "chats_chat_title_853c3234_uniq" DETAIL: Key (title)=(New Chat) already exists.
Model with a title field set to unique:
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)
Serializer for the chat:
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
And the 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)
It is specific to this API during creation of an object. What am I missing?
CodePudding user response:
This probably happens because the IntegrityError
exception is rised at the ORM level and is not handled by Django Rest Framework's default exception handler.
The best way I can think to fix this without rewriting the insides of ViewSet
is to define a custom exception handler as described here.
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
Then add this handler in settings.py
REST_FRAMEWORK = {
...
'EXCEPTION_HANDLER': 'utils.exceptions.integrity_error_exception_handler'
}
Also, you can use exc
and context
params to acces the original exception and view object in order to return more generic responses.