diff options
| author | Tom Christie | 2011-05-27 14:40:19 +0100 | 
|---|---|---|
| committer | Tom Christie | 2011-05-27 14:40:19 +0100 | 
| commit | 21d2dcc2942a8e4adb3a79b0983841e5f0ab5878 (patch) | |
| tree | 82acf04d4f092a392e6db51a7467c63406929a3c /djangorestframework | |
| parent | 9e9ae6094943d663a677b3bbe8e8af6a43744daf (diff) | |
| download | django-rest-framework-21d2dcc2942a8e4adb3a79b0983841e5f0ab5878.tar.bz2 | |
Allow .form specified on view.  Allow get_form, put_form, post_form.  Add .PARAMS.
Diffstat (limited to 'djangorestframework')
| -rw-r--r-- | djangorestframework/mixins.py | 23 | ||||
| -rw-r--r-- | djangorestframework/renderers.py | 19 | ||||
| -rw-r--r-- | djangorestframework/resources.py | 56 | ||||
| -rw-r--r-- | djangorestframework/templates/renderer.html | 22 | ||||
| -rw-r--r-- | djangorestframework/views.py | 5 | 
5 files changed, 72 insertions, 53 deletions
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py index 3c05bef0..11e3bb38 100644 --- a/djangorestframework/mixins.py +++ b/djangorestframework/mixins.py @@ -401,12 +401,23 @@ class ResourceMixin(object):      def CONTENT(self):          """          Returns the cleaned, validated request content. + +        May raise an :class:`response.ErrorResponse` with status code 400 (Bad Request).          """          if not hasattr(self, '_content'):              self._content = self.validate_request(self.DATA, self.FILES)          return self._content      @property +    def PARAMS(self): +        """ +        Returns the cleaned, validated query parameters. + +        May raise an :class:`response.ErrorResponse` with status code 400 (Bad Request). +        """ +        return self.validate_request(self.request.GET) + +    @property      def _resource(self):          if self.resource:              return self.resource(self) @@ -414,12 +425,14 @@ class ResourceMixin(object):              return ModelResource(self)          elif getattr(self, 'form', None):              return FormResource(self) +        elif getattr(self, '%s_form' % self.method.lower(), None): +            return FormResource(self)          return Resource(self) -    def validate_request(self, data, files): +    def validate_request(self, data, files=None):          """ -        Given the request *data* return the cleaned, validated content. -        Typically raises an :class:`response.ErrorResponse` with status code 400 (Bad Request) on failure. +        Given the request *data* and optional *files*, return the cleaned, validated content. +        May raise an :class:`response.ErrorResponse` with status code 400 (Bad Request) on failure.          """          return self._resource.validate_request(data, files) @@ -429,8 +442,8 @@ class ResourceMixin(object):          """          return self._resource.filter_response(obj) -    def get_bound_form(self, content=None): -        return self._resource.get_bound_form(content) +    def get_bound_form(self, content=None, method=None): +        return self._resource.get_bound_form(content, method=method) diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py index 245bfdfe..9834ba5e 100644 --- a/djangorestframework/renderers.py +++ b/djangorestframework/renderers.py @@ -172,7 +172,7 @@ class DocumentingTemplateRenderer(BaseRenderer):          return content -    def _get_form_instance(self, view): +    def _get_form_instance(self, view, method):          """          Get a form, possibly bound to either the input or output data.          In the absence on of the Resource having an associated form then @@ -180,22 +180,24 @@ class DocumentingTemplateRenderer(BaseRenderer):          """          # Get the form instance if we have one bound to the input -        form_instance = getattr(view, 'bound_form_instance', None) +        form_instance = None +        if method == view.method.lower(): +            form_instance = getattr(view, 'bound_form_instance', None)          if not form_instance and hasattr(view, 'get_bound_form'):              # Otherwise if we have a response that is valid against the form then use that              if view.response.has_content_body:                  try: -                    form_instance = view.get_bound_form(view.response.cleaned_content) +                    form_instance = view.get_bound_form(view.response.cleaned_content, method=method)                      if form_instance and not form_instance.is_valid():                          form_instance = None                  except:                      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() +                form_instance = view.get_bound_form(method=method)              except:                  pass @@ -250,7 +252,9 @@ class DocumentingTemplateRenderer(BaseRenderer):          needed to self-document the response to this request.          """          content = self._get_content(self.view, self.view.request, obj, media_type) -        form_instance = self._get_form_instance(self.view) + +        put_form_instance = self._get_form_instance(self.view, 'put') +        post_form_instance = self._get_form_instance(self.view, 'post')          if url_resolves(settings.LOGIN_URL) and url_resolves(settings.LOGOUT_URL):              login_url = "%s?next=%s" % (settings.LOGIN_URL, quote_plus(self.view.request.path)) @@ -282,7 +286,8 @@ class DocumentingTemplateRenderer(BaseRenderer):              'markeddown': markeddown,              'breadcrumblist': breadcrumb_list,              'available_media_types': self.view._rendered_media_types, -            'form': form_instance, +            'put_form': put_form_instance, +            'post_form': post_form_instance,              'login_url': login_url,              'logout_url': logout_url,              'ACCEPT_PARAM': getattr(self.view, '_ACCEPT_QUERY_PARAM', None), diff --git a/djangorestframework/resources.py b/djangorestframework/resources.py index de8e1351..1ac6eeac 100644 --- a/djangorestframework/resources.py +++ b/djangorestframework/resources.py @@ -122,7 +122,7 @@ class BaseResource(object):      def __init__(self, view):          self.view = view -    def validate_request(self, data, files): +    def validate_request(self, data, files=None):          """          Given the request content return the cleaned, validated content.          Typically raises a :exc:`response.ErrorResponse` with status code 400 (Bad Request) on failure. @@ -168,22 +168,12 @@ class FormResource(Resource):      """      The :class:`Form` class that should be used for request validation. -    This can be overridden by a :attr:`form` attribute on the :class:`.View`. +    This can be overridden by a :attr:`form` attribute on the :class:`views.View`.      """      form = None -    def __init__(self, view): -        """ -        Allow a :attr:`form` attributes set on the :class:`View` to override -        the :attr:`form` attribute set on the :class:`Resource`. -        """ -        super(FormResource, self).__init__(view) - -        if getattr(view, 'form', None): -            self.form = view.form - -    def validate_request(self, data, files): +    def validate_request(self, data, files=None):          """          Given some content as input return some cleaned, validated content.          Raises a :exc:`response.ErrorResponse` with status code 400 (Bad Request) on failure. @@ -285,18 +275,34 @@ class FormResource(Resource):          raise ErrorResponse(400, detail) -    def get_bound_form(self, data=None, files=None): +    def get_bound_form(self, data=None, files=None, method=None):          """          Given some content return a Django form bound to that content.          If form validation is turned off (:attr:`form` class attribute is :const:`None`) then returns :const:`None`.          """ -        if not self.form: + +        # A form on the view overrides a form on the resource. +        form = getattr(self.view, 'form', 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 method form on the view or resource overrides the general case. +        # Method forms are attributes like `get_form` `post_form` `put_form`. +        if method: +            form = getattr(self, '%s_form' % method.lower(), form) +            form = getattr(self.view, '%s_form' % method.lower(), form) + +        if not form:              return None          if data is not None: -            return self.form(data, files) +            return form(data, files) -        return self.form() +        return form() @@ -326,14 +332,14 @@ class ModelResource(FormResource):      The form class that should be used for request validation.      If set to :const:`None` then the default model form validation will be used. -    This can be overridden by a :attr:`form` attribute on the :class:`.View`. +    This can be overridden by a :attr:`form` attribute on the :class:`views.View`.      """      form = None      """      The model class which this resource maps to. -    This can be overridden by a :attr:`model` attribute on the :class:`.View`. +    This can be overridden by a :attr:`model` attribute on the :class:`views.View`.      """      model = None @@ -372,7 +378,7 @@ class ModelResource(FormResource):          if getattr(view, 'model', None):              self.model = view.model -    def validate_request(self, data, files): +    def validate_request(self, data, files=None):          """          Given some content as input return some cleaned, validated content.          Raises a :exc:`response.ErrorResponse` with status code 400 (Bad Request) on failure. @@ -389,7 +395,7 @@ class ModelResource(FormResource):          return self._validate(data, files, allowed_extra_fields=self._property_fields_set) -    def get_bound_form(self, data=None, files=None): +    def get_bound_form(self, data=None, files=None, method=None):          """          Given some content return a ``Form`` instance bound to that content. @@ -397,9 +403,11 @@ class ModelResource(FormResource):          to create the Form, otherwise the model will be used to create a ModelForm.          """ -        if self.form: -            # Use explict Form -            return super(ModelResource, self).get_bound_form(data, files) +        form = super(ModelResource, self).get_bound_form(data, files, method=method) +         +        # Use an explict Form if it exists +        if form: +            return form          elif self.model:              # Fall back to ModelForm which we create on the fly diff --git a/djangorestframework/templates/renderer.html b/djangorestframework/templates/renderer.html index 3010d712..09b17df7 100644 --- a/djangorestframework/templates/renderer.html +++ b/djangorestframework/templates/renderer.html @@ -58,19 +58,16 @@  			</form>  	{% endif %} -	{% comment %} *** Only display the POST/PUT/DELETE forms if we have a bound form, and if method     *** -	              *** tunneling via POST forms is enabled.                                              *** -	              *** (We could display only the POST form if method tunneling is disabled, but I think *** -	              ***  the user experience would be confusing, so we simply turn all forms off.         *** {% endcomment %} -	 -	{% if METHOD_PARAM and form %} +	{# Only display the POST/PUT/DELETE forms if method tunneling via POST forms is enabled. #}	 +	{% if METHOD_PARAM %} +  		{% if 'POST' in view.allowed_methods %} -				<form action="{{ request.path }}" method="post" {% if form.is_multipart %}enctype="multipart/form-data"{% endif %}> +				<form action="{{ request.path }}" method="post" {% if post_form.is_multipart %}enctype="multipart/form-data"{% endif %}>  				<fieldset class='module aligned'>  					<h2>POST {{ name }}</h2>  				    {% csrf_token %} -				    {{ form.non_field_errors }} -					{% for field in form %} +				    {{ post_form.non_field_errors }} +					{% for field in post_form %}  					<div class='form-row'>  					    {{ field.label_tag }}  					    {{ field }} @@ -86,13 +83,13 @@  		{% endif %}  		{% if 'PUT' in view.allowed_methods %} -				<form action="{{ request.path }}" method="post" {% if form.is_multipart %}enctype="multipart/form-data"{% endif %}> +				<form action="{{ request.path }}" method="post" {% if put_form.is_multipart %}enctype="multipart/form-data"{% endif %}>  				<fieldset class='module aligned'>  					<h2>PUT {{ name }}</h2>  					<input type="hidden" name="{{ METHOD_PARAM }}" value="PUT" />  					{% csrf_token %} -					{{ form.non_field_errors }} -					{% for field in form %} +					{{ put_form.non_field_errors }} +					{% for field in put_form %}  					<div class='form-row'>  					    {{ field.label_tag }}  					    {{ field }} @@ -119,6 +116,7 @@  				</fieldset>  				</form>  		{% endif %} +  	{% endif %}  	</div>  	</div> diff --git a/djangorestframework/views.py b/djangorestframework/views.py index 1315229a..5b3cc855 100644 --- a/djangorestframework/views.py +++ b/djangorestframework/views.py @@ -64,11 +64,6 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):      """      permissions = ( permissions.FullAnonAccess, ) -    # Allow name and description for the Resource to be set explicitly, -    # overiding the default classname/docstring behaviour. -    # These are used for documentation in the standard html and text renderers. -    name = None -    description = None      @classmethod      def as_view(cls, **initkwargs):  | 
