diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md index 4dc360598b..df383244a2 100644 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -184,6 +184,9 @@ For example: return FullAccountSerializer return BasicAccountSerializer +!!! note + If your implementation branches on `self.request.method`, note that the browsable API calls this method with the request method overridden while [rendering its forms][browsable-api-form-rendering]. + **Save and deletion hooks**: The following methods are provided by the mixin classes, and provide easy overriding of the object save or deletion behavior. @@ -416,6 +419,7 @@ The following third party packages provide additional generic view implementatio [cite]: https://docs.djangoproject.com/en/stable/ref/class-based-views/#base-vs-generic-views +[browsable-api-form-rendering]: ../topics/browsable-api.md#form-rendering [GenericAPIView]: #genericapiview [ListModelMixin]: #listmodelmixin [CreateModelMixin]: #createmodelmixin diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index f78d81b166..41b790ee56 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -171,6 +171,8 @@ Renders data into HTML for the Browsable API: This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page. +It also renders an HTML form for each method the view allows, which involves calling back into the view with the request method overridden. See [form rendering][browsable-api-form-rendering] for the implications of this. + **.media_type**: `text/html` **.format**: `'api'` @@ -513,6 +515,7 @@ Comma-separated values are a plain-text tabular data format, that can be easily [cite]: https://docs.djangoproject.com/en/stable/ref/template-response/#the-rendering-process +[browsable-api-form-rendering]: ../topics/browsable-api.md#form-rendering [conneg]: content-negotiation.md [html-and-forms]: ../topics/html-and-forms.md [browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers diff --git a/docs/topics/browsable-api.md b/docs/topics/browsable-api.md index dd2da68778..e9adc938e9 100644 --- a/docs/topics/browsable-api.md +++ b/docs/topics/browsable-api.md @@ -29,6 +29,12 @@ urlpatterns = [ ``` +## Form rendering + +In order to render the HTML forms, the browsable API needs to know which fields each form should contain, so it asks the view for a serializer once per form. Each of those calls is made with the request method overridden to match the form being rendered, rather than the method that was actually used for the request. + +This means that during a `GET` request the view may be called again with `self.request.method` set to `POST`, `PUT`, `PATCH`, `DELETE` or `OPTIONS`. Any code that branches on the request method will observe the overridden value. Two common cases are a `get_serializer_class()` implementation that returns a different serializer for read and write operations, and permission classes, which are checked for each method before its form is rendered. This is expected behavior, and only affects rendering of the browsable API. + ## Customizing The browsable API is built with [Twitter's Bootstrap][bootstrap] (v 3.4.1), making it easy to customize the look-and-feel.