From 580031a9149f29fdd96674f22b83e3124877b7a7 Mon Sep 17 00:00:00 2001 From: "Sean C. Farley" Date: Mon, 9 Apr 2012 14:28:04 -0400 Subject: [PATCH 1/3] Add GET method form handling Add handling of forms for the GET method. The code requires the form for the GET method to be explicitly declared (e.g., get_form = AGetForm); the form attribute will only be used for POST and PUT but not GET. --- djangorestframework/renderers.py | 8 ++++++-- djangorestframework/resources.py | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py index d9aa4028e..e40865b62 100644 --- a/djangorestframework/renderers.py +++ b/djangorestframework/renderers.py @@ -251,8 +251,10 @@ class DocumentingTemplateRenderer(BaseRenderer): except Exception: pass - # If we still don't have a form instance then try to get an unbound form which can tunnel arbitrary content types - if not form_instance: + # If we still don't have a form instance then try to get an unbound form + # which can tunnel arbitrary content types. Forms for the GET method + # must be explicit, so do not create a generic form. + if not form_instance and method != 'get': form_instance = self._get_generic_content_form(view) return form_instance @@ -316,6 +318,7 @@ class DocumentingTemplateRenderer(BaseRenderer): content = self._get_content(self.view, self.view.request, obj, media_type) + get_form_instance = self._get_form_instance(self.view, 'get') put_form_instance = self._get_form_instance(self.view, 'put') post_form_instance = self._get_form_instance(self.view, 'post') @@ -342,6 +345,7 @@ class DocumentingTemplateRenderer(BaseRenderer): 'version': VERSION, 'breadcrumblist': breadcrumb_list, 'available_formats': self.view._rendered_formats, + 'get_form': get_form_instance, 'put_form': put_form_instance, 'post_form': post_form_instance, 'FORMAT_PARAM': self._FORMAT_QUERY_PARAM, diff --git a/djangorestframework/resources.py b/djangorestframework/resources.py index f170eb45a..a4ca8a508 100644 --- a/djangorestframework/resources.py +++ b/djangorestframework/resources.py @@ -182,15 +182,19 @@ class FormResource(Resource): """ Returns the form class used to validate this resource. """ - # A form on the view overrides a form on the resource. - form = getattr(self.view, 'form', None) or self.form - # Use the requested method or determine the request method if method is None and hasattr(self.view, 'request') and hasattr(self.view, 'method'): method = self.view.method elif method is None and hasattr(self.view, 'request'): method = self.view.request.method + # A form on the view overrides a form on the resource. The GET method + # must have its form explicity set (e.g., get_form). + if not method or method.lower() != 'get': + form = getattr(self.view, 'form', None) or self.form + else: + form = None + # A method form on the view or resource overrides the general case. # Method forms are attributes like `get_form` `post_form` `put_form`. if method: From b5f986abddad0d3559052c63761ec3d0a68ab4f8 Mon Sep 17 00:00:00 2001 From: "Sean C. Farley" Date: Tue, 10 Apr 2012 12:23:06 -0400 Subject: [PATCH 2/3] Avoid unbound form for GET instance Do not attempt to get an unbound form for an instance using a GET method. This results in the same issue as getting a generic form where an explicit form must be provided for an instance obtained using the GET method. --- djangorestframework/renderers.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py index e40865b62..a72ebaf11 100644 --- a/djangorestframework/renderers.py +++ b/djangorestframework/renderers.py @@ -244,18 +244,20 @@ class DocumentingTemplateRenderer(BaseRenderer): except Exception: form_instance = None - # If we still don't have a form instance then try to get an unbound form - if not form_instance: - try: - form_instance = view.get_bound_form(method=method) - except Exception: - pass + # Forms for the GET method must be explicit, so do not get an unbound + # form nor create a generic form for this instance. + if method != 'get': + # If we still don't have a form instance then try to get an unbound form + if not form_instance: + try: + form_instance = view.get_bound_form(method=method) + except Exception: + pass - # If we still don't have a form instance then try to get an unbound form - # which can tunnel arbitrary content types. Forms for the GET method - # must be explicit, so do not create a generic form. - if not form_instance and method != 'get': - form_instance = self._get_generic_content_form(view) + # If we still don't have a form instance then try to get an unbound form + # which can tunnel arbitrary content types. + if not form_instance: + form_instance = self._get_generic_content_form(view) return form_instance From 87d06697f7738873901c5c3c64a992e0b5bf7497 Mon Sep 17 00:00:00 2001 From: "Sean C. Farley" Date: Tue, 26 Jun 2012 17:56:38 -0400 Subject: [PATCH 3/3] Pass request to related serializers Related serializers may need access to the request to properly serialize a child resource. For example, reverse() in djangorestframework.reverse uses request if available to return an absolute URL. While the parent resource has access to the request to generate the absolute URL, the child resource does not. --- djangorestframework/serializer.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/djangorestframework/serializer.py b/djangorestframework/serializer.py index 9481eeff1..57050bd83 100644 --- a/djangorestframework/serializer.py +++ b/djangorestframework/serializer.py @@ -179,7 +179,8 @@ class Serializer(object): stack = self.stack[:] stack.append(obj) - return related_serializer(depth=depth, stack=stack).serialize(obj) + return related_serializer(depth=depth, stack=stack).serialize( + obj, request=self.request) def serialize_max_depth(self, obj): """ @@ -258,6 +259,10 @@ class Serializer(object): Convert any object into a serializable representation. """ + # Request from related serializer. + if request is not None: + self.request = request + if isinstance(obj, (dict, models.Model)): # Model instances & dictionaries return self.serialize_model(obj)