Reputation: 7384
In Django Rest Framework I did the seriailizers, viewsets and routers approach. Whenever I POST with an intentional error in the API view of django rest framework it throws an Integrity Error. Is there a way to try and catch the errors like if there is no errors in the data just proceed to save however if there are errors throw a JSON Response with the list of errors like:
[{'section':'This field can not be blank', 'first_name':'This field can not be blank', 'middle_name':'This field can not be blank', 'last_name':'This field can not be blank'}]
models.py
from django.db import models
# Create your models here.
# class AuditTable(models.Model):
# date_created = models.DateTimeField(auto_now_add=True)
# test_field = models.CharField(max_length=50, null=True, blank=True)
class Section(models.Model):
name = models.CharField(max_length=50, default=None)
def __str__(self):
return self.name
class Student(models.Model):
section = models.ForeignKey(Section, default=None)
first_name = models.CharField(max_length=50, default=None)
middle_name = models.CharField(max_length=50, default=None)
last_name = models.CharField(max_length=50, default=None)
def __str__(self):
full_name = "%s %s %s" % (self.first_name, self.middle_name, self.last_name)
return full_name
serializers.py
from rest_framework import serializers
from rest_framework.response import Response
from . models import *
class SectionSerializer(serializers.ModelSerializer):
class Meta:
model = Section
fields = ('name', )
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ('section', 'first_name', 'middle_name', 'last_name' )
viewsets.py
from rest_framework import viewsets
from . serializers import *
from . models import *
class SectionViewSet(viewsets.ModelViewSet):
queryset = Section.objects.all()
serializer_class = SectionSerializer
class StudentViewSet(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
routers.py
from rest_framework import routers
from . viewsets import *
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register(r'students', StudentViewSet)
router.register(r'sections', SectionViewSet)
urls.py
from django.conf.urls import include, url
from . import views
from . routers import router
urlpatterns = [
url(r'^$', views.index, name='testing_sample_index' ),
url(r'^restful-form/$', views.web_service_form, name='testing_sample_web_service' ),
url(r'^api/', include(router.urls)),
]
Upvotes: 5
Views: 3711
Reputation: 4174
There is a better (in my opinion) solution: Django Rest Framework has a EXCEPTION_HANDLER that allows to customly handle exceptions not handled by default by it.
So, you have to:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'applications.utils.exception_handler'
}
def exception_handler(exc, context):
"""
Handle Django ValidationError as an accepted exception by DRF.
For the parameters, see ``exception_handler``
"""
if isinstance(exc, IntegrityError):
exc = DRFValidationError(detail=exc)
return drf_exception_handler(exc, context)
Now, whenever an IntegrityError is raised that DRF's serializer doesn't handle, this function will translate it to DRFValidationError which will be properly handled returning a 400 error with a proper data.
Upvotes: 1
Reputation: 9636
As per this answer, the solution would be:
viewsets.py
from django.db import IntegrityError # Import IntegrityError
from rest_framework import viewsets
from rest_framework.exceptions import APIException #Import APIException
from . serializers import *
from . models import *
class SectionViewSet(viewsets.ModelViewSet):
queryset = Section.objects.all()
serializer_class = SectionSerializer
def create(self, request, *args, **kwargs):
try:
return super().create(request, *args, **kwargs)
except IntegrityError as exc:
raise APIException(detail=exc)
Upvotes: 7
Reputation: 20996
If you have an IntegrityError
then your models aren't up to date with your database.
You should set uniqueness constraint to match your DB scheme.
Note that DRF can validate against unique constraints with the UniqueValidator
Upvotes: 5
Reputation: 5993
The default CreateMixin
implementation raises an exception on any validation error. So you could write your own custom mixin...
class VerboseCreateModelMixin(object):
"""
Create a model instance and return either created object or the validation errors.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
...and then use it in your ViewSet
:
class SectionViewSet(VerboseCreateModelMixin, viewsets.ModelViewSet):
queryset = Section.objects.all()
serializer_class = SectionSerializer
Upvotes: 4