Django REST Framework API Guide (1) : Requesting Django REST Framework API Guide (2) : Responding to Django REST Framework API Guide (3) : Views Django REST Framework API Guide (4) : Generic Views Django REST Framework API Guide (5) : View Sets Django REST Framework API Guide (6) : Django REST Framework API Guide (7) : Parsing Django REST Framework API Guide (8) : Rendering

Link to official text

Apply colours to a drawing

The REST Framework contains a number of built-in renderer classes that allow you to return responses using various media types. Custom renderers are also supported.

How do I determine which renderer to use

A view’s collection of renderers is always defined as a list of classes. When a view is invoked, the REST Framework analyzes the requested content and determines the most appropriate renderer to satisfy the request. The basic process of content analysis involves checking the Accept header of a request to determine the media type it expects in the response. Alternatively, make it explicit with the format suffix on the URL. For example, the URL http://example.com/api/users_count.json may always return JSON data.

Setting up the renderer

DEFAULT_RENDERER_CLASSES can be used to set the global default set of renderers. For example, the following setup uses JSON as the primary media type and also includes a self-describing API.

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer'.'rest_framework.renderers.BrowsableAPIRenderer')},Copy the code

You can also use apiView-based view classes to set up renderers for individual views or sets of views.

from django.contrib.auth.models import User
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView

class UserCountView(APIView):
    """ A view that returns the count of active users in JSON. """
    renderer_classes = (JSONRenderer, )

    def get(self, request, format=None):
        user_count = User.objects.filter(active=True).count()
        content = {'user_count': user_count}
        return Response(content)
Copy the code

Or on a function view based on the @API_view decorator.

@api_view(['GET'])
@renderer_classes((JSONRenderer,))
def user_count_view(request, format=None):
    """ A view that returns the count of active users in JSON. """
    user_count = User.objects.filter(active=True).count()
    content = {'user_count': user_count}
    return Response(content)
Copy the code

The priority of the renderer class

When specifying renderer classes for apis, it is important to consider their priority in handling each media type. If the client does not specify a representation of the accepted data, such as sending Accept: */* header, or containing no Accept header at all, the REST Framework selects the first renderer in the list for use in the response.

For example, if your API provides JSON responses and browsable HTML apis, you may need to use the JSONRenderer as the default renderer to send JSON responses to clients that do not specify Accept headers.

If your API contains views that handle both regular web pages and API responses on request, you might consider setting the TemplateHTMLRenderer as the default to work well with older browsers that send broken Accept Headers.

API reference

JSONRenderer

Render the request data as JSON using UTF-8 encoding.

Note that the default style contains Unicode characters and renders the response in a compact style (without excess whitespace) :

{"unicode black star":"★"."value":999}
Copy the code

The client may also include an “indented” media type parameter, in which case the returned JSON will be indented.

For example: Accept: application/json; Indent = 4.

{
    "unicode black star": "★"."value": 999
}
Copy the code

You can change the default JSON encoding style using the UNICODE_JSON and COMPACT_JSON Settings keys.

Media_type: application/json

Format: ‘json’

The charset: None

TemplateHTMLRenderer

Use Django’s standard templates to render the data as HTML. Unlike other renderers, the data passed to Response does not need to be serialized. In addition, you may need to include the template_name parameter when creating Response.

TemplateHTMLRenderer creates a RequestContext, uses Response.data as the context dictionary, and determines the name of the template used to render the context.

Template names are determined (in order of precedence) :

  1. Explicitly passed to responsetemplate_nameParameters.
  2. Set explicit on this class.template_nameProperties.
  3. callview.get_template_names()Returns the result of.

Example of a view using TemplateHTMLRenderer:

class UserDetail(generics.RetrieveAPIView):
    """ A view that returns a templated HTML representation of a given user. """
    queryset = User.objects.all()
    renderer_classes = (TemplateHTMLRenderer,)

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return Response({'user': self.object}, template_name='user_detail.html')
Copy the code

You can use the TemplateHTMLRenderer to make the REST framework return regular HTML pages, or to return HTML and API responses from a single endpoint.

If you’re building a site that uses TemplateHTMLRenderer and other renderer classes, consider listing TemplateHTMLRenderer as the first class in the renderer_classes list, So that even browsers that send ill-formatted ACCEPT: header will take precedence over it.

. Media_type: text/HTML

Format: ‘HTML’

The charset: utf-8

StaticHTMLRenderer

A simple renderer that simply returns pre-rendered HTML. Unlike other renderers, the data passed to the response object should be a string representing what is to be returned.

Example of a view using the StaticHTMLRenderer:

@api_view(('GET',))
@renderer_classes((StaticHTMLRenderer,))
def simple_html_view(request):
    data = '<html><body><h1>Hello, world</h1></body></html>'
    return Response(data)
Copy the code

You can use the StaticHTMLRenderer to get the REST Framework to return regular HTML pages, or to return HTML and API responses from a single endpoint.

. Media_type: text/HTML

Format: ‘HTML’

The charset: utf-8

BrowsableAPIRenderer

Render data as browsable HTML API:

This renderer determines which other renderers are given the highest priority and uses it to display apI-style responses in HTML pages.

. Media_type: text/HTML

Format: ‘API’

The charset: utf-8

The template: ‘rest_framework/API. HTML’

Custom BrowsableAPIRenderer

By default, the response content will be rendered with the highest priority renderer except BrowsableAPIRenderer. If you need to customize this behavior, for example, by using HTML as the default return format but using JSON in a browsable API, you can do so by overriding the get_default_renderer() method.

Such as:

class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
    def get_default_renderer(self, view):
        return JSONRenderer()
Copy the code

AdminRenderer

Render the data as HTML to display admin-like content:

The renderer works with a CRUD-style Web API, which should also provide a user-friendly interface for managing data.

Note that the AdminRenderer does not work for views that nest or list serialized input, because the HTML form does not support them properly.

Note: AdminRenderer can only contain links to detailed pages when there is a properly configured URL_FIELD_NAME (url by default) property in the data. For HyperlinkedModelSerializer, such is the case, but for ModelSerializer class or conventional Serializer class, you need to ensure that clear contains the fields. For example, here we use the model get_absolute_url method:

class AccountSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)

    class Meta:
        model = Account
Copy the code

. Media_type: text/HTML

Format: ‘admin’

The charset: utf-8

The template: ‘rest_framework/admin. HTML’

HTMLFormRenderer

Render the serialized returned data as an HTML form. The renderer’s output does not contain a closed

tag, hidden CSRF input, or any submit buttons.

This renderer is not used directly, but can be used in a template by passing an instance of the serializer to the Render_form template tag.

{% load rest_framework %}

<form action="/submit-report/" method="post">
    {% csrf_token %}
    {% render_form serializer %}
    <input type="submit" value="Save" />
</form>
Copy the code

. Media_type: text/HTML

Format: ‘form’

The charset: utf-8

The template: ‘rest_framework/horizontal/form. HTML’

MultiPartRenderer

This renderer is used to render HTML Multipart form data. It is not suitable as a response renderer, but is used to create test requests, using the REST Framework’s test client and test request factory.

Media_type: multipart/form – data; boundary=BoUnDaRyStRiNg

Format: ‘multipart’

The charset: utf-8

Custom renderer

To implement a custom renderer, you should inherit BaseRenderer, set the.media_type and.format properties, Render (self, data, media_type=None, renderer_Context =None).

This method should return a string that will be used as the body of the HTTP response.

The arguments passed to the.render() method are:

data

Request data, set when Response() is instantiated.

media_type=None

Optional. If provided, this is the type of media accepted, as determined by the Content negotiation stage.

Depending on the client’s Accept: header, it can be more specific than the renderer’s mediA_type property and may contain media-type arguments. Such as “application/json; Nested = true “.

renderer_context=None

Optional. If provided, it is the dictionary of context information provided by the view.

By default, this will include the following keys: View, Request, Response, args, kwargs.

Take a chestnut

Here is an example plain text renderer that returns a response with data parameters as the content of the response.

from django.utils.encoding import smart_unicode
from rest_framework import renderers


class PlainTextRenderer(renderers.BaseRenderer):
    media_type = 'text/plain'
    format = 'txt'

    def render(self, data, media_type=None, renderer_context=None):
        return data.encode(self.charset)
Copy the code

Set the charset

By default, renderer classes are assumed to use UTF-8 encoding. To use a different encoding, set the Charset property on the renderer.

class PlainTextRenderer(renderers.BaseRenderer):
    media_type = 'text/plain'
    format = 'txt'
    charset = 'iso-8859-1'

    def render(self, data, media_type=None, renderer_context=None):
        return data.encode(self.charset)
Copy the code

Note that if the renderer class returns a Unicode string, the Response content will be forced to be a ByteString by the Response class. Set the Charset property on the renderer to determine the encoding.

If the renderer returns a string representing raw binary Content, the charset value should be set to None, which ensures that the response’s Content-Type header does not set the charset value.

In some cases, you may also want to set the render_style property to ‘binary’. Doing so will also ensure that browsable apis do not attempt to display binary content as strings.

class JPEGRenderer(renderers.BaseRenderer):
    media_type = 'image/jpeg'
    format = 'jpg'
    charset = None
    render_style = 'binary'

    def render(self, data, media_type=None, renderer_context=None):
        return data
Copy the code

Advanced use of renderers

You can use REST Framework renderers to do some very flexible things. For example…

  • Provide flat or nested representations from the same endpoint, depending on the media type requested.
  • Handles both regular HTML web pages and JSON-based API responses from the same endpoint.
  • Specify the various HTML representations used by the API client.
  • Do not explicitly specify the media type of the renderer, such as the usemedia_type ='image/*'And the use ofAcceptHeader changes the encoding of the response.

Media Type changes

In some cases, you might want the view to use a different serialization style depending on the media type it receives. If you need to do so, visit request.accepted_renderer to determine the negotiate renderer that will be used in response.

Such as:

@api_view(('GET',))
@renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def list_users(request):
    """ A view that can return JSON or HTML representations of the users in the system. """
    queryset = Users.objects.filter(active=True)

    if request.accepted_renderer.format == 'html':
        # TemplateHTMLRenderer takes a context dict,
        # and additionally requires a 'template_name'.
        # It does not require serialization.
        data = {'users': queryset}
        return Response(data, template_name='list_users.html')

    # JSONRenderer requires serialized data as normal.
    serializer = UserSerializer(instance=queryset)
    data = serializer.data
    return Response(data)
Copy the code

Unclear media type

In some cases, a renderer may be required to provide a range of media types. In this case, you can specify the media type it should respond to by using a media_type value, such as image/* or */*.

If the renderer’s media Type is not explicitly specified, make sure that the media type is explicitly specified using the content_type attribute when the response is returned. Such as:

return Response(data, content_type='image/png')
Copy the code

Design your media type

For many Web API purposes, a simple JSON response with a hyperlink relationship might be sufficient. If you want to fully embrace RESTful design and HATEOAS, you need to think about the design and use of media types in more detail.

HTML error view

In general, the renderer behaves the same whether it handles a regular response, a response that raises an exception (such as an Http404 or PermissionDenied exception), or a response from a subclass of APIException.

If you use a TemplateHTMLRenderer or StaticHTMLRenderer and throw an exception, youll behave slightly differently, reflecting Django’s default handling of error views.

Exceptions thrown and handled by the HTML renderer will attempt to render using one of the following methods, in order of precedence.

  • Load and render the template{status_code}.html.
  • Load and render the templateapi_exception.html.
  • Render the HTTP status code and text, such as “404 Not Found”.

The template will be rendered using RequestContext, which contains the status_code and details keys.

Note: If DEBUG = True, Django’s standard error traceback page is displayed instead of the HTTP status code and text.