Skip to content

Content Negotiation ​

Content negotiation is the process of selecting the most appropriate data format to return to a client based on their preferences. In DRF, content negotiation acts as the routing mechanism that decides exactly which Parser and which Renderer should be used for a given request.

How it works ​

DRF relies on standard HTTP headers to perform this routing:

  • Parsing (Incoming Data): DRF examines the Content-Type header of the incoming request to determine which Parser should process request.data. (e.g., Content-Type: application/json routes to the JSONParser).
  • Rendering (Outgoing Data): DRF examines the Accept header to determine which Renderer should format the response. (e.g., Accept: text/html might route to the BrowsableAPIRenderer or TemplateHTMLRenderer).

Default Behavior ​

By default, DRF uses DefaultContentNegotiation. This class respects the client's Accept headers but will gracefully fall back to the first renderer in your renderer_classes list if the client's preferences cannot be strictly met.

You can explicitly set or override this globally in your settings.py:

python
REST_FRAMEWORK = {
    'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation'
}

Or on a per-view basis:

Class-Based Views ​

python
from rest_framework.negotiation import DefaultContentNegotiation
from rest_framework.views import APIView

class ExampleView(APIView):
    content_negotiation_class = DefaultContentNegotiation

NOTE

Function-based views (@api_view) always use the globally configured content negotiation class. DRF does not provide a decorator to override this on a per-view basis for FBVs.

Custom Content Negotiation ​

While DefaultContentNegotiation handles 99% of use cases, you might need a custom scheme. For example, you might want to completely ignore the client's Accept headers and always force a specific response format based on the URL or the requesting user's profile.

To implement a custom scheme, subclass BaseContentNegotiation and override the .select_parser() and .select_renderer() methods.

python
from rest_framework.negotiation import BaseContentNegotiation

class IgnoreClientContentNegotiation(BaseContentNegotiation):
    """
    A custom negotiator that ignores client headers and simply 
    forces the first available parser and renderer defined on the view.
    """
    def select_parser(self, request, parsers):
        # `parsers` is the list of Parser instances configured on the view
        return parsers[0]

    def select_renderer(self, request, renderers, format_suffix):
        # `renderers` is the list of Renderer instances configured on the view
        # `format_suffix` is an optional URL suffix (like '.json' or '.xml')
        
        # Return a tuple of (Renderer instance, Media type string)
        return (renderers[0], renderers[0].media_type)

By returning the renderer and media type directly, you explicitly dictate how the Response will be formatted, bypassing standard HTTP negotiation rules entirely.