From d07dc77e91c1f99b47915b3cef30b565f2618e82 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 5 Oct 2012 10:23:47 +0100 Subject: Accepted media type uses most specific of client/renderer media types. --- docs/api-guide/generic-views.md | 29 +++++++++++++++++++++++------ docs/api-guide/renderers.md | 14 +++++++------- 2 files changed, 30 insertions(+), 13 deletions(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md index b2284ae5..571cc66f 100644 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -18,24 +18,25 @@ If the generic views don't suit the needs of your API, you can drop down to usin Typically when using the generic views, you'll override the view, and set several class attributes. class UserList(generics.ListCreateAPIView): - serializer = UserSerializer model = User - permissions = (IsAdminUser,) + serializer_class = UserSerializer + permission_classes = (IsAdminUser,) paginate_by = 100 For more complex cases you might also want to override various methods on the view class. For example. class UserList(generics.ListCreateAPIView): - serializer = UserSerializer model = User - permissions = (IsAdminUser,) + serializer_class = UserSerializer + permission_classes = (IsAdminUser,) def get_paginate_by(self): """ Use smaller pagination for HTML representations. """ - if self.request.accepted_media_type == 'text/html': - return 10 + page_size_param = self.request.QUERY_PARAMS.get('page_size') + if page_size_param: + return int(page_size_param) return 100 For very simple cases you might want to pass through any class attributes using the `.as_view()` method. For example, your URLconf might include something the following entry. @@ -52,24 +53,32 @@ Used for read-only endpoints to represent a collection of model instances. Provides a `get` method handler. +Extends: [MultipleObjectBaseAPIView], [ListModelMixin] + ## ListCreateAPIView Used for read-write endpoints to represent a collection of model instances. Provides `get` and `post` method handlers. +Extends: [MultipleObjectBaseAPIView], [ListModelMixin], [CreateModelMixin] + ## RetrieveAPIView Used for read-only endpoints to represent a single model instance. Provides a `get` method handler. +Extends: [SingleObjectBaseAPIView], [RetrieveModelMixin] + ## RetrieveUpdateDestroyAPIView Used for read-write endpoints to represent a single model instance. Provides `get`, `put` and `delete` method handlers. +Extends: [SingleObjectBaseAPIView], [RetrieveModelMixin], [UpdateModelMixin], [DestroyModelMixin] + --- # Base views @@ -123,3 +132,11 @@ Provides a `.destroy(request, *args, **kwargs)` method, that implements deletion [SingleObjectMixin]: https://docs.djangoproject.com/en/dev/ref/class-based-views/mixins-single-object/ [multiple-object-mixin-classy]: http://ccbv.co.uk/projects/Django/1.4/django.views.generic.list/MultipleObjectMixin/ [single-object-mixin-classy]: http://ccbv.co.uk/projects/Django/1.4/django.views.generic.detail/SingleObjectMixin/ + +[SingleObjectBaseAPIView]: #singleobjectbaseapiview +[MultipleObjectBaseAPIView]: #multipleobjectbaseapiview +[ListModelMixin]: #listmodelmixin +[CreateModelMixin]: #createmodelmixin +[RetrieveModelMixin]: #retrievemodelmixin +[UpdateModelMixin]: #updatemodelmixin +[DestroyModelMixin]: #destroymodelmixin \ No newline at end of file diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index 134c3749..e1c83477 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -115,7 +115,6 @@ For example: @api_view(('GET',)) @renderer_classes((TemplateHTMLRenderer, JSONRenderer)) - @template_name('list_users.html') def list_users(request): """ A view that can return JSON or HTML representations @@ -123,15 +122,16 @@ For example: """ queryset = Users.objects.filter(active=True) - if request.accepted_renderer.format == 'html': + if request.accepted_media_type == 'text/html': # TemplateHTMLRenderer takes a context dict, - # and does not require serialization. + # and additionally requiresa 'template_name'. + # It does not require serialization. data = {'users': queryset} - else: - # JSONRenderer requires serialized data as normal. - serializer = UserSerializer(instance=queryset) - data = serializer.data + return Response(data, template='list_users.html') + # JSONRenderer requires serialized data as normal. + serializer = UserSerializer(instance=queryset) + data = serializer.data return Response(data) ## Designing your media types -- cgit v1.2.3 From 26c7d6df6c0a12a2e19e07951b93de80bbfdf91c Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 5 Oct 2012 12:13:44 +0100 Subject: HTMLTemplateRenderer working --- docs/api-guide/renderers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index e1c83477..ef0ed46f 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -127,7 +127,7 @@ For example: # and additionally requiresa 'template_name'. # It does not require serialization. data = {'users': queryset} - return Response(data, template='list_users.html') + return Response(data, template_name='list_users.html') # JSONRenderer requires serialized data as normal. serializer = UserSerializer(instance=queryset) -- cgit v1.2.3 From 2575ea92aad3608142cfdd3ede5ee1b53e2064ba Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 5 Oct 2012 13:04:34 +0100 Subject: Docs for template responses --- docs/api-guide/renderers.md | 19 ++++++++++++++- docs/api-guide/responses.md | 56 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 6 deletions(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index ef0ed46f..d2d8985d 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -86,11 +86,28 @@ If your API includes views that can serve both regular webpages and API response ## DocumentingHTMLRenderer +Renders data into HTML for the browseable 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. + **.media_type:** `text/html` **.format:** `'.api'` -## TemplateHTMLRenderer +## HTMLTemplateRenderer + +Renders data to HTML, using Django's standard template rendering. +Unlike other renderers, the data passed to the `Response` does not need to be serialized. Also, unlike other renderers, you may want to include a `template_name` argument when creating the `Response`. + +The HTMLTemplateRenderer will create a `RequestContext`, using the `response.data` as the context dict, and determine a template name to use to render the context. + +The template name is determined by (in order of preference): + +1. An explicit `.template_name` attribute set on the response. +2. An explicit `.template_name` attribute set on this class. +3. The return result of calling `view.get_template_names()`. + +You can use `HTMLTemplateRenderer` either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint. + +If you're building websites that use `HTMLTemplateRenderer` along with other renderer classes, you should consider listing `HTMLTemplateRenderer` as the first class in the `renderer_classes` list, so that it will be prioritised first even for browsers that send poorly formed ACCEPT headers. **.media_type:** `text/html` diff --git a/docs/api-guide/responses.md b/docs/api-guide/responses.md index e9ebcf81..d8f8e97c 100644 --- a/docs/api-guide/responses.md +++ b/docs/api-guide/responses.md @@ -14,7 +14,11 @@ There's no requirement for you to use the `Response` class, you can also return Unless you want to heavily customize REST framework for some reason, you should always use an `APIView` class or `@api_view` function for views that return `Response` objects. Doing so ensures that the view can perform content negotiation and select the appropriate renderer for the response, before it is returned from the view. -## Response(data, status=None, headers=None) +--- + +# Methods + +## Response(data, status=None, template_name=None, headers=None) Unlike regular `HttpResponse` objects, you do not instantiate `Response` objects with rendered content. Instead you pass in unrendered data, which may consist of any python primatives. @@ -22,16 +26,58 @@ The renderers used by the `Response` class cannot natively handle complex dataty You can use REST framework's `Serializer` classes to perform this data serialization, or use your own custom serialization. +Arguments: + +* `data`: The serialized data for the response. +* `status`: A status code for the response. Defaults to 200. See also [status codes][statuscodes]. +* `template_name`: A template name to use if `HTMLTemplateRenderer` is selected. +* `headers`: A dictionary of HTTP headers to use in the response. + +## .render() + +This methd is called to render the serialized data of the response into the final response content. When `.render()` is called, the response content will be set to the result of calling the `.render(data, accepted_media_type)` method on the accepted renderer instance. + +You won't typically need to call `.render()` yourself, as it's handled by Django's standard response cycle. + +## Standard HTTPResponse methods + +The `Response` class extends `SimpleTemplateResponse`, and all the usual methods are also available on the response. For example you can set headers on the response in the standard way: + + response = Response() + response['Cache-Control'] = 'no-cache' + +--- + +# Attributes + ## .data The unrendered content of a `Request` object can be accessed using the `.data` attribute. +## .status_code + +The numeric status code of the HTTP response. + ## .content -To access the rendered content of a `Response` object, you must first call `.render()`. You'll typically only need to do this in cases such as unit testing responses - when you return a `Response` from a view Django's response cycle will handle calling `.render()` for you. +The rendered content of the response. `.render()` must have been called before `.content` can be accessed. + +## .template_name + +The `template_name`, if supplied. Only required if `HTMLTemplateRenderer` or some other custom template renderer is the accepted renderer for the reponse. + +## .accepted_renderer + +The renderer instance that will be used to render the response. + +Set automatically by the `APIView` or `@api_view` immediately before the response is returned from the view. + +## .accepted_media_type + +The media type that was selected by the content negotiation stage. -## .renderer +Set automatically by the `APIView` or `@api_view` immediately before the response is returned from the view. -When you return a `Response` instance, the `APIView` class or `@api_view` decorator will select the appropriate renderer, and set the `.renderer` attribute on the `Response`, before returning it from the view. -[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/ \ No newline at end of file +[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/ +[statuscodes]: status-codes.md \ No newline at end of file -- cgit v1.2.3