From 5105e53b7aab31b6ab20b220883fe622bc62c2de Mon Sep 17 00:00:00 2001 From: Radoslav Georgiev Date: Fri, 28 Dec 2018 19:24:43 +0200 Subject: [PATCH] Move code samples to `utils.py` --- README.md | 2 ++ utils.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/README.md b/README.md index a2ba52e..9859da5 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,8 @@ class CourseCreateApi( return Response(status=status.HTTP_201_CREATED) ``` +All of code above can be found in `utils.py` in this repository. + ## Inspiration The way we do Django is inspired by the following things: diff --git a/utils.py b/utils.py index 36c1f6c..a750fc5 100644 --- a/utils.py +++ b/utils.py @@ -1,3 +1,9 @@ +from rest_framework import serializers +from rest_framework import exceptions as rest_exceptions + +from django.core.exceptions import ValidationError + + def create_serializer_class(name, fields): return type(name, (serializers.Serializer, ), fields) @@ -9,3 +15,46 @@ def inline_serializer(*, fields, data=None, **kwargs): return serializer_class(data=data, **kwargs) return serializer_class(**kwargs) + + +def get_first_matching_attr(obj, *attrs, default=None): + for attr in attrs: + if hasattr(obj, attr): + return getattr(obj, attr) + + return default + + +def get_error_message(exc): + if hasattr(exc, 'message_dict'): + return exc.message_dict + error_msg = get_first_matching_attr(exc, 'message', 'messages') + + if isinstance(error_msg, list): + error_msg = ', '.join(error_msg) + + if error_msg is None: + error_msg = str(exc) + + return error_msg + + +class ExceptionHandlerMixin: + """ + Mixin that transforms Django and Python exceptions into rest_framework ones. + without the mixin, they return 500 status code which is not desired. + """ + expected_exceptions = { + ValueError: rest_exceptions.ValidationError, + ValidationError: rest_exceptions.ValidationError, + PermissionError: rest_exceptions.PermissionDenied + } + + def handle_exception(self, exc): + if isinstance(exc, tuple(self.expected_exceptions.keys())): + drf_exception_class = self.expected_exceptions[exc.__class__] + drf_exception = drf_exception_class(get_error_message(exc)) + + return super().handle_exception(drf_exception) + + return super().handle_exception(exc)