diff --git a/rest_framework/views.py b/rest_framework/views.py index a709c2f6b..39f072df0 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import inspect import warnings +from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import PermissionDenied from django.http import Http404 from django.utils import six @@ -90,6 +91,12 @@ def exception_handler(exc, context): set_rollback() return Response(data, status=status.HTTP_403_FORBIDDEN) + elif isinstance(exc, DjangoValidationError): + msg = _('Validation error.') + data = {'detail': exc.messages} + + set_rollback() + return Response(data, status=status.HTTP_400_BAD_REQUEST) # Note: Unhandled exceptions will raise a 500 error. return None diff --git a/tests/test_views.py b/tests/test_views.py index 65024609c..0b08bf689 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import copy import sys +from django.core.validators import validate_ipv4_address from django.test import TestCase from rest_framework import status @@ -19,6 +20,8 @@ if sys.version_info[:2] >= (3, 4): else: JSON_ERROR = 'JSON parse error - No JSON object could be decoded' +IPV4_VALIDATION_ERROR = ['Enter a valid IPv4 address.'] + class BasicView(APIView): def get(self, request, *args, **kwargs): @@ -50,6 +53,18 @@ def error_view(request): raise Exception +class ValidationErrorView(APIView): + def get(self, request, *args, **kwargs): + 'raises a django ValidtionError by calling the ip4 validation function with a bad input' + validate_ipv4_address('a.b.c.d') + + +@api_view(['GET']) +def validation_error_view(request): + 'raises a django ValidtionError by calling the ip4 validation function with a bad input' + validate_ipv4_address('a.b.c.d') + + def sanitise_json_error(error_dict): """ Exact contents of JSON error messages depend on the installed version @@ -148,3 +163,27 @@ class TestCustomExceptionHandler(TestCase): expected = 'Error!' self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.data, expected) + + +class TestDjangoValidationErrorHandlling(TestCase): + def test_class_based_validation_error_handling(self): + view = ValidationErrorView.as_view() + + request = factory.get('/') + response = view(request) + expected = { + 'detail': IPV4_VALIDATION_ERROR + } + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data, expected) + + def test_function_based_validation_error_handling(self): + view = validation_error_view + + request = factory.get('/') + response = view(request) + expected = { + 'detail': IPV4_VALIDATION_ERROR + } + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data, expected)