Formatting django rest serializer error

Saheed Adedeji
3 min readMay 29, 2021

--

Django rest framework has been a very reliable framework for creating API. While it has a lot of features, some of these features can be frustrating for other parties (Front End) to work with. Example of such feature is the serializer error.

Serializer has been a great support as it helps with validating the payload passed. The main issue has been the way the validation errors coming back from these serializers are being sent as response.

A sample of this is shown below

models.py

class Company(models.Model):name = models.CharField(max_length=100)sector = models.CharField(max_length=100)description = models.TextField()time_created = models.TimeField(auto_now_add=True)date_created = models.DateField(auto_now_add=True)def __str__(self):self.name

serializers.py

class CompanySerializer(ModelSerializer):
class Meta:
model = Companyfields = ‘__all__’

views.py

class CompanyViewSet(ModelViewSet):queryset = Company.objects.all()serializer_class = CompanySerializer

urls.py

router = DefaultRouter()
router.register(‘companys’, CompanyViewSet)

The error returned after a failed request is as formatted below

The issue with this response is that most Front End developers want their response in a format where both the json key and value are string. Whereas the implementation above shows the key as string while the value is returned as list. Django actually validates all possible errors for a field hence the list, as a field can have more than one error.

Printing the serializer errors at this stage, the response is displayed below

print(serializer.errors)

{'name': [ErrorDetail(string='This field is required.', code='required')], 'sector': [ErrorDetail(string='This field is required.', code='required')], 'description': [ErrorDetail(string='This field is required.', code='required')]}

As show above, each error include a field name and field error that can be printed with

for field_name, field_errors in serializer.errors.items():print(field_name, field_errors)

With the response

name [ErrorDetail(string='This field is required.', code='required')]
sector [ErrorDetail(string='This field is required.', code='required')]
description [ErrorDetail(string='This field is required.', code='required')]

As shown above, the field names are name, code and description while the error detail is a list consisting of the string (message) and the code (error cause), thus with these information you can format the errors and send it in any form you prefer. As shown below

views.py

class CompanyViewSet(ModelViewSet):queryset = Company.objects.all()serializer_class = CompanySerializerdef create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)if serializer.is_valid():serializer.save()return Response({'status': 'Successful'}, status=status.HTTP_201_CREATED)else:default_errors = serializer.errorsfield_names = []for field_name, field_errors in default_errors.items():field_names.append(field_name)return Response({'error': f'Invalid data in {field_names}'}, status=status.HTTP_400_BAD_REQUEST)

The reformatted views.py will generate the response shown below

To display all errors, the views can also be formatted in another way

class CompanyViewSet(ModelViewSet):queryset = Company.objects.all()serializer_class = CompanySerializerdef create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)if serializer.is_valid():serializer.save()return Response({'status': 'Successful'}, status=status.HTTP_201_CREATED)else:default_errors = serializer.errorsnew_error = {}for field_name, field_errors in default_errors.items():new_error[field_name] = field_errors[0]return Response(new_error, status=status.HTTP_400_BAD_REQUEST)

And will generate the response below

The response can be shown in any format, also note that though i chose to format the code in the views.py, the same result can be achieved by reformatting the serializers.py, adding a function as a property of the serializer class to do this.

Never intended for the post to be this long. Wish you all the best.!!!

--

--

Responses (2)