diff options
Diffstat (limited to 'rest_framework/views.py')
| -rw-r--r-- | rest_framework/views.py | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/rest_framework/views.py b/rest_framework/views.py index bc870417..12bb78bd 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -2,6 +2,8 @@ Provides an APIView class that is the base of all views in REST framework. """ from __future__ import unicode_literals +import inspect +import warnings from django.core.exceptions import PermissionDenied from django.http import Http404 @@ -46,7 +48,7 @@ def get_view_description(view_cls, html=False): return description -def exception_handler(exc): +def exception_handler(exc, context): """ Returns the response that should be used for any given exception. @@ -93,6 +95,7 @@ class APIView(View): permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS metadata_class = api_settings.DEFAULT_METADATA_CLASS + versioning_class = api_settings.DEFAULT_VERSIONING_CLASS # Allow dependency injection of other settings to make testing easier. settings = api_settings @@ -184,6 +187,18 @@ class APIView(View): 'request': getattr(self, 'request', None) } + def get_exception_handler_context(self): + """ + Returns a dict that is passed through to EXCEPTION_HANDLER, + as the `context` argument. + """ + return { + 'view': self, + 'args': getattr(self, 'args', ()), + 'kwargs': getattr(self, 'kwargs', {}), + 'request': getattr(self, 'request', None) + } + def get_view_name(self): """ Return the view name, as used in OPTIONS responses and in the @@ -300,6 +315,16 @@ class APIView(View): if not throttle.allow_request(request, self): self.throttled(request, throttle.wait()) + def determine_version(self, request, *args, **kwargs): + """ + If versioning is being used, then determine any API version for the + incoming request. Returns a two-tuple of (version, versioning_scheme) + """ + if self.versioning_class is None: + return (None, None) + scheme = self.versioning_class() + return (scheme.determine_version(request, *args, **kwargs), scheme) + # Dispatch methods def initialize_request(self, request, *args, **kwargs): @@ -308,11 +333,13 @@ class APIView(View): """ parser_context = self.get_parser_context(request) - return Request(request, - parsers=self.get_parsers(), - authenticators=self.get_authenticators(), - negotiator=self.get_content_negotiator(), - parser_context=parser_context) + return Request( + request, + parsers=self.get_parsers(), + authenticators=self.get_authenticators(), + negotiator=self.get_content_negotiator(), + parser_context=parser_context + ) def initial(self, request, *args, **kwargs): """ @@ -329,6 +356,10 @@ class APIView(View): neg = self.perform_content_negotiation(request) request.accepted_renderer, request.accepted_media_type = neg + # Determine the API version, if versioning is in use. + version, scheme = self.determine_version(request, *args, **kwargs) + request.version, request.versioning_scheme = version, scheme + def finalize_response(self, request, response, *args, **kwargs): """ Returns the final response object. @@ -369,7 +400,18 @@ class APIView(View): else: exc.status_code = status.HTTP_403_FORBIDDEN - response = self.settings.EXCEPTION_HANDLER(exc) + exception_handler = self.settings.EXCEPTION_HANDLER + + if len(inspect.getargspec(exception_handler).args) == 1: + warnings.warn( + 'The `exception_handler(exc)` call signature is deprecated. ' + 'Use `exception_handler(exc, context) instead.', + PendingDeprecationWarning + ) + response = exception_handler(exc) + else: + context = self.get_exception_handler_context() + response = exception_handler(exc, context) if response is None: raise |
