aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework/contentnegotiation.py
diff options
context:
space:
mode:
authorTom Christie2012-09-14 23:17:12 +0100
committerTom Christie2012-09-14 23:17:12 +0100
commit6543ccd244a8d482b8aec18b5d03ee964292f17f (patch)
tree72e0ae8812e3606d53cd117156d633e1833c75fc /djangorestframework/contentnegotiation.py
parent5036638d0c8a9f53d865e7b6bfd11b4a5534ba6e (diff)
downloaddjango-rest-framework-6543ccd244a8d482b8aec18b5d03ee964292f17f.tar.bz2
Cleaner content negotiation. Occurs after permissions. Optional 'force' flag.
Diffstat (limited to 'djangorestframework/contentnegotiation.py')
-rw-r--r--djangorestframework/contentnegotiation.py35
1 files changed, 32 insertions, 3 deletions
diff --git a/djangorestframework/contentnegotiation.py b/djangorestframework/contentnegotiation.py
index 223919ef..1c646ca7 100644
--- a/djangorestframework/contentnegotiation.py
+++ b/djangorestframework/contentnegotiation.py
@@ -1,24 +1,40 @@
from djangorestframework import exceptions
from djangorestframework.settings import api_settings
from djangorestframework.utils.mediatypes import order_by_precedence
+from django.http import Http404
import re
MSIE_USER_AGENT_REGEX = re.compile(r'^Mozilla/[0-9]+\.[0-9]+ \([^)]*; MSIE [0-9]+\.[0-9]+[a-z]?;[^)]*\)(?!.* Opera )')
class BaseContentNegotiation(object):
- def determine_renderer(self, request, renderers):
- raise NotImplementedError('.determine_renderer() must be implemented')
+ def negotiate(self, request, renderers, format=None, force=False):
+ raise NotImplementedError('.negotiate() must be implemented')
class DefaultContentNegotiation(object):
settings = api_settings
- def negotiate(self, request, renderers):
+ def negotiate(self, request, renderers, format=None, force=False):
"""
Given a request and a list of renderers, return a two-tuple of:
(renderer, media type).
+
+ If force is set, then suppress exceptions, and forcibly return a
+ fallback renderer and media_type.
+ """
+ try:
+ return self._negotiate(request, renderers, format)
+ except (Http404, exceptions.NotAcceptable):
+ if force:
+ return (renderers[0], renderers[0].media_type)
+ raise
+
+ def _negotiate(self, request, renderers, format=None):
+ """
+ Actual implementation of negotiate, inside the 'force' wrapper.
"""
+ renderers = self.filter_renderers(renderers, format)
accepts = self.get_accept_list(request)
# Check the acceptable media types against each renderer,
@@ -33,6 +49,19 @@ class DefaultContentNegotiation(object):
raise exceptions.NotAcceptable(available_renderers=renderers)
+ def filter_renderers(self, renderers, format):
+ """
+ If there is a '.json' style format suffix, only use
+ renderers that accept that format.
+ """
+ if not format:
+ return renderers
+
+ renderers = [renderer for renderer in renderers
+ if renderer.can_handle_format(format)]
+ if not renderers:
+ raise Http404()
+
def get_accept_list(self, request):
"""
Given the incoming request, return a tokenised list of