Django REST Framework how to specify error code when raising validation error in serializer
django, django-rest-framework
Solution
You can raise different exceptions like:
from rest_framework.exceptions import APIException
from django.utils.encoding import force_text
from rest_framework import status
class CustomValidation(APIException):
status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
default_detail = 'A server error occurred.'
def __init__(self, detail, field, status_code):
if status_code is not None:self.status_code = status_code
if detail is not None:
self.detail = {field: force_text(detail)}
else: self.detail = {'detail': force_text(self.default_detail)}
you can use this in your serializer like:
raise CustomValidation('Duplicate Username','username', status_code=status.HTTP_409_CONFLICT)
or
raise CustomValidation('Access denied','username', status_code=status.HTTP_403_FORBIDDEN)
Problem
I have an API endpoint that allow users to register an account. I would like to return HTTP 409 instead of 400 for a duplicate username. Here is my serializer: ``` from django.contrib.auth.models import User from rest_framework.serializers import ModelSerializer class UserSerializer(ModelSerializer): username = CharField() def validate_username(self, value): if User.objects.filter(username=value).exists(): raise NameDuplicationError() return value class NameDuplicationError(APIException): status_code = status.HTTP_409_CONFLICT default_detail = u'Duplicate Username' ``` When the error is triggered, the response is: `{"detail":"Duplicate Username"}`. I realised that if I subclass APIException, the key `detail` is used instead of `username`. I want to have this response instead `{"username":"Duplicate Username"}` or I would like to specify a status code when raising a ValidationError: ``` def validate_username(self, value): if User.objects.filter(username=value).exists(): raise serializers.ValidationError('Duplicate Username', status_code=status.HTTP_409_CONFLICT) return value ``` But this does not work as `ValidationError` only returns 400. Is there any other way to accomplish this?