diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py index ab290ffff..99f6719b3 100644 --- a/djangorestframework/mixins.py +++ b/djangorestframework/mixins.py @@ -4,7 +4,7 @@ from django.contrib.auth.models import AnonymousUser from django.db.models.query import QuerySet from django.db.models.fields.related import RelatedField from django.http import HttpResponse -from django.http.multipartparser import LimitBytes # TODO: Use LimitedStream in compat +from django.http.multipartparser import LimitBytes from djangorestframework import status from djangorestframework.parsers import FormParser, MultiPartParser @@ -87,7 +87,8 @@ class RequestMixin(object): content_length = int(request.META.get('CONTENT_LENGTH', request.META.get('HTTP_CONTENT_LENGTH'))) except (ValueError, TypeError): content_length = 0 - + + # TODO: Add 1.3's LimitedStream to compat and use that. # Currently only supports parsing request body as a stream with 1.3 if content_length == 0: return None @@ -116,6 +117,8 @@ class RequestMixin(object): #except (ValueError, TypeError): # content_length = 0 # self._stream = LimitedStream(request, content_length) + # + # UPDATE: http://code.djangoproject.com/ticket/15785 self._stream = request else: self._stream = StringIO(request.raw_post_data) @@ -227,7 +230,7 @@ class RequestMixin(object): @property def default_parser(self): """Return the view's most preferred renderer. - (This has no behavioural effect, but is may be used by documenting renderers)""" + (This has no behavioral effect, but is may be used by documenting renderers)""" return self.parsers[0] @@ -244,17 +247,17 @@ class ResponseMixin(object): """ Adds behavior for pluggable Renderers to a :class:`.BaseView` or Django :class:`View`. class. - Default behaviour is to use standard HTTP Accept header content negotiation. - Also supports overidding the content type by specifying an _accept= parameter in the URL. + Default behavior is to use standard HTTP Accept header content negotiation. + Also supports overriding the content type by specifying an _accept= parameter in the URL. Ignores Accept headers from Internet Explorer user agents and uses a sensible browser Accept header instead. """ - ACCEPT_QUERY_PARAM = '_accept' # Allow override of Accept header in URL query params REWRITE_IE_ACCEPT_HEADER = True renderers = () - - + + # TODO: wrap this behavior around dispatch(), ensuring it works well with + # existing Django classes that use render_to_response. def render(self, response): """ Takes a ``Response`` object and returns an ``HttpResponse``. @@ -284,10 +287,12 @@ class ResponseMixin(object): def _determine_renderer(self, request): - """Return the appropriate renderer for the output, given the client's 'Accept' header, + """ + Return the appropriate renderer for the output, given the client's 'Accept' header, and the content types that this mixin knows how to serve. - See: RFC 2616, Section 14 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html""" + See: RFC 2616, Section 14 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + """ if self.ACCEPT_QUERY_PARAM and request.GET.get(self.ACCEPT_QUERY_PARAM, None): # Use _accept parameter override @@ -351,13 +356,17 @@ class ResponseMixin(object): @property def renderted_media_types(self): - """Return an list of all the media types that this resource can render.""" + """ + Return an list of all the media types that this resource can render. + """ return [renderer.media_type for renderer in self.renderers] @property def default_renderer(self): - """Return the resource's most preferred renderer. - (This renderer is used if the client does not send and Accept: header, or sends Accept: */*)""" + """ + Return the resource's most preferred renderer. + (This renderer is used if the client does not send and Accept: header, or sends Accept: */*) + """ return self.renderers[0] @@ -367,8 +376,6 @@ class AuthMixin(object): """ Simple mixin class to provide authentication and permission checking, by adding a set of authentication and permission classes on a ``View``. - - TODO: wrap this behavior around dispatch() """ authentication = () permissions = () @@ -391,6 +398,7 @@ class AuthMixin(object): return user return AnonymousUser() + # TODO: wrap this behavior around dispatch() def _check_permissions(self): """ Check user permissions and either raise an ``ErrorResponse`` or return. diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py index d18a8a373..73809b5ed 100644 --- a/djangorestframework/renderers.py +++ b/djangorestframework/renderers.py @@ -1,8 +1,9 @@ """ Renderers are used to serialize a View's output into specific media types. -django-rest-framework also provides HTML and PlainText renderers that help self-document the API, -by serializing the output along with documentation regarding the Resource, output status and headers, -and providing forms and links depending on the allowed methods, renderers and parsers on the Resource. + +Django REST framework also provides HTML and PlainText renderers that help self-document the API, +by serializing the output along with documentation regarding the View, output status and headers, +and providing forms and links depending on the allowed methods, renderers and parsers on the View. """ from django import forms from django.conf import settings @@ -33,8 +34,8 @@ __all__ = ( class BaseRenderer(object): """ - All renderers must extend this class, set the media_type attribute, and - override the render() function. + All renderers must extend this class, set the media_type attribute, + and override the render() function. """ media_type = None @@ -43,13 +44,20 @@ class BaseRenderer(object): def render(self, obj=None, media_type=None): """ + Given an object render it into a string. + + The requested media type is also passed to this method, + as it may contain parameters relevant to how the parser + should render the output. + EG: 'application/json; indent=4' + By default render simply returns the ouput as-is. Override this method to provide for other behavior. """ if obj is None: return '' - return obj + return str(obj) class TemplateRenderer(BaseRenderer): @@ -101,10 +109,8 @@ class DocumentingTemplateRenderer(BaseRenderer): """Get a form, possibly bound to either the input or output data. In the absence on of the Resource having an associated form then provide a form that can be used to submit arbitrary content.""" - # Get the form instance if we have one bound to the input - #form_instance = resource.form_instance - # TODO! Reinstate this + # Get the form instance if we have one bound to the input form_instance = getattr(view, 'bound_form_instance', None) if not form_instance and hasattr(view, 'get_bound_form'): @@ -183,7 +189,7 @@ class DocumentingTemplateRenderer(BaseRenderer): if apply_markdown: try: markeddown = apply_markdown(description) - except AttributeError: # TODO: possibly split the get_description / get_name into a mixin class + except AttributeError: markeddown = None breadcrumb_list = get_breadcrumbs(self.view.request.path)