Commits

Russell Keith-Magee  committed 0d0ccfe

Filled in the blanks on alternate return types.

  • Participants
  • Parent commits a470a4c
  • Branches class-based-views

Comments (0)

Files changed (1)

File docs/topics/class-based-views.txt

 More than just HTML
 -------------------
 
-todo:Simple JSON dispatching
+So far, we've been focusing on rendering templates to generate
+responses. However, that's not all generic views can do.
+
+Each generic view is composed out of a series of mixins, and each
+mixin contributes a little piece of the entire view. Some of these
+mixins -- such as
+:class:`~django.views.generic.base.TemplateResponseMixin` -- are
+specifically designed for rendering content to a HTML response using a
+template. However, you can write your own mixins that perform
+different rendering behavior.
+
+For example, you a simple JSON mixin might look something like this::
+
+    class JSONResponseMixin(object):
+        def render_to_response(self, context):
+            "Returns a JSON response containing 'context' as payload"
+            return self.get_json_response(self.convert_context_to_json(context))
+
+        def get_json_response(self, content, **httpresponse_kwargs):
+            "Construct an `HttpResponse` object."
+            return http.HttpResponse(content,
+                                     content_type='application/json',
+                                     **httpresponse_kwargs)
+
+        def convert_context_to_json(self, context):
+            "Convert the context dictionary into a JSON object"
+            # Note: This is *EXTREMELY* naive; in reality, you'll need
+            # to do much more complex handling to ensure that arbitrary
+            # objects -- such as Django model instances or querysets
+            # -- can be serialized as JSON.
+            return json.dumps(content)
+
+Then, you could build a JSON-returning
+:class:`~django.views.generic.detail.DetailView` by mixing your
+:class:`JSONResponseMixin` with the
+:class:`~django.views.generic.detail.BaseDetailView` -- (the
+:class:`~django.views.generic.detail.DetailView` before template
+rendering behavior has been mixed in)::
+
+    class JSONDetailView(JSONResponseMixin, BaseDetailView):
+        pass
+
+This view can then be deployed in the same way as any other
+:class:`~django.views.generic.detail.DetailView`, with exactly the
+same behavior -- except for the format of the response.
+
+If you want to be really adventurous, you could even mix a
+:class:`~django.views.generic.detail.DetailView` subclass that is able
+to return *both* HTML and JSON content, depending on some property of
+the HTTP request, such as a query argument or a HTTP header. Just mix
+in both the :class:`JSONResponseMixin` and a
+:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
+and override the implementation of :func:`render_to_response()` to defer
+to the appropriate subclass depending on the type of response that the user
+requested::
+
+    class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
+        def render_to_response(self, context):
+            # Look for a 'format=json' GET argument
+            if self.request.GET.get('format','html') == 'json':
+                return JSONResponseMixin.render_to_response(self, context)
+            else:
+                return SingleObjectTemplateResponseMixin.render_to_response(self, context)
+
+Because of the way that Python resolves method overloading, the local
+:func:``render_to_response()`` implementation will override the
+versions provided by :class:`JSONResponseMixin` and
+:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.