From 4179982dc999207fe61221a44662bfe87940a1ea Mon Sep 17 00:00:00 2001 From: Shaun Stanworth Date: Mon, 13 May 2013 17:55:45 +0100 Subject: [PATCH 1/2] `show_form_for_method` expects request object with appropriate method pre-attached --- rest_framework/renderers.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 1917a0803..285b35672 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -336,7 +336,7 @@ class BrowsableAPIRenderer(BaseRenderer): return # Cannot use form overloading try: - view.check_permissions(clone_request(request, method)) + view.check_permissions(request) except exceptions.APIException: return False # Doesn't have permissions return True @@ -379,7 +379,9 @@ class BrowsableAPIRenderer(BaseRenderer): provide a form that can be used to submit arbitrary content. """ obj = getattr(view, 'object', None) - if not self.show_form_for_method(view, method, request, obj): + cloned_request = clone_request(request, method) + + if not self.show_form_for_method(view, method, cloned_request, obj): return if method in ('DELETE', 'OPTIONS'): @@ -413,7 +415,8 @@ class BrowsableAPIRenderer(BaseRenderer): # Check permissions obj = getattr(view, 'object', None) - if not self.show_form_for_method(view, method, request, obj): + cloned_request = clone_request(request, method) + if not self.show_form_for_method(view, method, cloned_request, obj): return content_type_field = api_settings.FORM_CONTENTTYPE_OVERRIDE From 2d49567e8862ef8082822638765ad89dba9f01ca Mon Sep 17 00:00:00 2001 From: Shaun Stanworth Date: Tue, 14 May 2013 15:05:39 +0100 Subject: [PATCH 2/2] `get_serializer` can now be told the specific request it's building it for --- rest_framework/generics.py | 29 ++++++++++++++++++++++++----- rest_framework/renderers.py | 2 +- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 05ec93d37..b2c5cea9d 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -2,6 +2,7 @@ Generic views that provide commonly needed behaviour. """ from __future__ import unicode_literals +import inspect from django.core.exceptions import ImproperlyConfigured from django.core.paginator import Paginator, InvalidPage @@ -66,13 +67,30 @@ class GenericAPIView(views.APIView): 'view': self } + def _get_serializer_class(self, request): + """ + The signature of get_serializer_class can be request-specific now. + """ + if len(inspect.getargspec(self.get_serializer_class).args) != 2: + warnings.warn( + '`get_serializer_class` now expects to be provided the request ' + 'object directly.', DeprecationWarning, stacklevel=2 + ) + old_request = self.request + try: + self.request = request + return self.get_serializer_class() + finally: + self.request = old_request + return self.get_serializer_class(request) + def get_serializer(self, instance=None, data=None, - files=None, many=False, partial=False): + files=None, many=False, partial=False, request=None): """ Return the serializer instance that should be used for validating and deserializing input, and for serializing output. """ - serializer_class = self.get_serializer_class() + serializer_class = self._get_serializer_class(request or self.request) context = self.get_serializer_context() return serializer_class(instance, data=data, files=files, many=many, partial=partial, context=context) @@ -83,7 +101,8 @@ class GenericAPIView(views.APIView): """ class SerializerClass(self.pagination_serializer_class): class Meta: - object_serializer_class = self.get_serializer_class() + object_serializer_class = self._get_serializer_class( + self.request) pagination_serializer_class = SerializerClass context = self.get_serializer_context() @@ -193,7 +212,7 @@ class GenericAPIView(views.APIView): return self.paginate_by - def get_serializer_class(self): + def get_serializer_class(self, request): """ Return the class to use for the serializer. Defaults to using `self.serializer_class`. @@ -201,7 +220,7 @@ class GenericAPIView(views.APIView): You may want to override this if you need to provide different serializations depending on the incoming request. - (Eg. admins get full serialization, others get basic serilization) + (Eg. admins get full serialization, others get basic serialization) """ serializer_class = self.serializer_class if serializer_class is not None: diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 285b35672..2f8212d74 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -390,7 +390,7 @@ class BrowsableAPIRenderer(BaseRenderer): if not getattr(view, 'get_serializer', None) or not parsers.FormParser in view.parser_classes: return - serializer = view.get_serializer(instance=obj) + serializer = view.get_serializer(instance=obj, request=cloned_request) fields = self.serializer_to_form_fields(serializer) # Creating an on the fly form see: