-
-
Save twidi/9d55486c36b6a51bdcb05ce3a763e79f to your computer and use it in GitHub Desktop.
""" | |
Sometimes in your Django model you want to raise a ``ValidationError`` in the ``save`` method, for | |
some reason. | |
This exception is not managed by Django Rest Framework because it occurs after its validation | |
process. So at the end, you'll have a 500. | |
Correcting this is as simple as overriding the exception handler, by converting the Django | |
``ValidationError`` to a DRF one. | |
""" | |
from django.core.exceptions import ValidationError as DjangoValidationError | |
from rest_framework.exceptions import ValidationError as DRFValidationError | |
from rest_framework.views import exception_handler as drf_exception_handler | |
def exception_handler(exc, context): | |
"""Handle Django ValidationError as an accepted exception | |
Must be set in settings: | |
>>> REST_FRAMEWORK = { | |
... # ... | |
... 'EXCEPTION_HANDLER': 'mtp.apps.common.drf.exception_handler', | |
... # ... | |
... } | |
For the parameters, see ``exception_handler`` | |
""" | |
if isinstance(exc, DjangoValidationError): | |
exc = DRFValidationError(detail=exc.message_dict) | |
return drf_exception_handler(exc, context) |
If you think about it... this must have been done already.
As DRF has this ModelSerializer, which magically handles Django's validation just fine (like the ones raised by Model.clean
method as well as the validators you specified for your fields)
Here's where the magic happens:
https://github.com/encode/django-rest-framework/blob/master/rest_framework/fields.py
rest_framework.fields.get_error_detail
and here is where it's used, very nicely implemented.
rest_framework.fields.Field.run_validators
https://github.com/encode/django-rest-framework/blob/master/rest_framework/fields.py
and rest_framework.serializers.Serializer.as_serializer_error
https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py
You should be able to handle it like this:
from django.core.exceptions import ValidationError as DjangoValidationError
from rest_framework.exceptions import ValidationError as DRFValidationError
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.fields import get_error_detail
def exception_handler(exc, context):
if isinstance(exc, DjangoValidationError):
exc = DRFValidationError(detail=get_error_detail(exc))
return drf_exception_handler(exc, context)
Please what is the context and how do I pass that to the django view?
Very helpful snippet. Thanks!