diff options
Diffstat (limited to 'rest_framework/views.py')
| -rw-r--r-- | rest_framework/views.py | 65 | 
1 files changed, 55 insertions, 10 deletions
| diff --git a/rest_framework/views.py b/rest_framework/views.py index bc870417..b4abc4d9 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -2,10 +2,11 @@  Provides an APIView class that is the base of all views in REST framework.  """  from __future__ import unicode_literals -  from django.core.exceptions import PermissionDenied  from django.http import Http404 +from django.utils import six  from django.utils.encoding import smart_text +from django.utils.translation import ugettext_lazy as _  from django.views.decorators.csrf import csrf_exempt  from rest_framework import status, exceptions  from rest_framework.compat import HttpResponseBase, View @@ -13,6 +14,8 @@ from rest_framework.request import Request  from rest_framework.response import Response  from rest_framework.settings import api_settings  from rest_framework.utils import formatting +import inspect +import warnings  def get_view_name(view_cls, suffix=None): @@ -46,7 +49,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. @@ -72,11 +75,13 @@ def exception_handler(exc):          return Response(data, status=exc.status_code, headers=headers)      elif isinstance(exc, Http404): -        data = {'detail': 'Not found'} +        msg = _('Not found.') +        data = {'detail': six.text_type(msg)}          return Response(data, status=status.HTTP_404_NOT_FOUND)      elif isinstance(exc, PermissionDenied): -        data = {'detail': 'Permission denied'} +        msg = _('Permission denied.') +        data = {'detail': six.text_type(msg)}          return Response(data, status=status.HTTP_403_FORBIDDEN)      # Note: Unhandled exceptions will raise a 500 error. @@ -93,6 +98,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 +190,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 +318,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 +336,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 +359,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 +403,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.', +                DeprecationWarning +            ) +            response = exception_handler(exc) +        else: +            context = self.get_exception_handler_context() +            response = exception_handler(exc, context)          if response is None:              raise | 
