On Wed, 2009-01-21 at 01:32 -0800, Guyon Morée wrote:
> Hi,
>
> I've built a bunch of 'normal' views rendering templates and
> processing POST's.
>
> Now, I'd like to build a API for my site, based on JSON. When building
> this API I noticed most of the views are 99% the same,
Excellent. :-)
That's the ideal situation.
> except for
> outputting JSON instead of HTML templates.
>
> Any ideas how I could reduce duplication of code in these cases?
A rough "general" pattern here is that most of your view is constructing
a dictionary of values -- and it could be some other data structure, but
we'll assume a dictionary here -- that will be used to generate the
output. For templates, this dictionary is usually just passed to a
Context class to create the template context. But there might be some
other transformation you have to do to it first.
In any case, that's where the split happens. One function is responsible
for collecting the output data and putting it into a neutral data
structure -- again, let's say, a dictionary. That output data will be
the same, no matter what the format of the response.
Then you decide, based on the request, whether to process that data into
a json response, or an Atom response, or an HTML templated response.
Each of those "convert the dictionary into an output response" could be
another function. Those functions might have to do some further munging
of the dictionary for their own circumstances -- for example, the
template version might drop in some extra variables for "the current
page" or something related to tab ids -- but, by and large, they'll all
be handing off the data to a different renderer. Either
simplejson.dumps, or render_to_string (or render_to_response) or
whatever.
In pseudo-code:
def my_view(request, ....):
result_data = gather_the_data(...)
if response_type == "html":
return render_to_html(request, result_data)
if response_type == "json":
return HttpResponse(render_to_json(request,
result_data))
def render_to_html(request, result_data):
template_name =
get_template_name(result_data["target_name"])
return render_to_response(template_name, result_data)
def render_to_json(request, result_data):
return simplejson.dumps(result_data)
This is very simplistic, but it hopefully gets the idea across.
"result_data" is the neutral form, gather_the_data() does all the heavy
lifting and the various presentation functions do the final bit.
Depending on how your code works out, it's probably going to be easy to
make this all more regular, too. A function to work out the response
type, which is then used as a key to look up a dictionary of
presentation functions to call (render_to_html, render_to_json, etc).
Daniel Lindsley has a blog post about a version of this that uses
templates for all the output formats -- see [1]. I tend to go for the
"presentation functions" approach, since templates don't feel like the
right solution for json or Atom. But the principle is the same and
Daniel's post (and a follow-up one James Bennett did at [2]) should give
you some more ideas.
[1] http://toastdriven.com/fresh/multiresponse/
[2] http://www.b-list.org/weblog/2008/nov/29/multiresponse/
Regards,
Malcolm
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---