diff options
| author | Tom Christie | 2012-09-14 23:17:12 +0100 |
|---|---|---|
| committer | Tom Christie | 2012-09-14 23:17:12 +0100 |
| commit | 6543ccd244a8d482b8aec18b5d03ee964292f17f (patch) | |
| tree | 72e0ae8812e3606d53cd117156d633e1833c75fc /djangorestframework/contentnegotiation.py | |
| parent | 5036638d0c8a9f53d865e7b6bfd11b4a5534ba6e (diff) | |
| download | django-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.py | 35 |
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 |
