Question

I'm relatively new to Django, and I'm using version 1.5 to build a REST api. Calls to the api expect JSON to be returned (I'm using this with an Ember.js front-end).

I'm wondering if I can't do something like this:

def listproject(request, pk_id):
  # list single project at /projects/<pk_id>
  project = Project.objects.get(pk = pk_id)
  snapshots = Snapshot.objects.filter(project = project)

  # (both are same up to here)

  return render_to_response('project.json',
    {"project":project, "snapshots":snapshots},
    mimetype="text/json")

Where project.json is this Django template:

{
  "id": "{{ project.pk }}",
  "name": "{{ project.name }}",
  "snapshot_ids": [ {% for snapshot in snapshots %}"{{ snapshot.pk }}"{% if not forloop.last %}, {% endif %}{% endfor %}
}

Someone who has worked with Django much longer than I have is suggesting that using templates for this will be inefficient. He suggests I do the following instead:

def listproject(request, pk_id):
  # list single project at /projects/<pk_id>
  project = Project.objects.get(pk = pk_id)
  snapshots = Snapshot.objects.filter(project = project)

  # (both are same up to here)

  ret_json = []
  ret_json.append('{"id": "' + str(project.pk) + '", ')
  ret_json.append('"name": "' + project.name + '", "snapshot_ids": [')

  snapshot_json = []
  for snapshot in snapshots:
    snapshot_json.append('"' + str(snapshot.pk) + '",')
  ret_json.append(''.join(snapshot_json)[0:-1] + ']}')

  return HttpResponse(content=''.join(ret_json), mimetype="text/json")

I've tested both. They work identically, though my version produces more readable JSON.

Please help us end our debate! Which is more efficient (and why)?

Was it helpful?

Solution

It's true that Django templates are not particularly efficient. However, that's only really a problem when you have very large templates that themselves extend or include many other templates, for example in a complex content management system. With a single template containing a small number of fields like you have, template rendering is insignificant compared to the overall overhead of serving the request.

That said I'm a bit confused about both of your alternatives. Why aren't you generating JSON via the standard json library? That's the proper way to do it, not by building up strings either in templates or in Python code.

ret = {'id': project.id,
       'name': project.name,
       'snapshot_ids': [snapshot.id for snapshot in snapshots]}
ret_json = json.dumps(ret)

OTHER TIPS

Both of these options look horrible to me. I'd prefer to avoid 'hand-writing' the JSON as much as possible and just convert directly from Python data structures.

Fortunately the json module is designed for this.

import json

def listproject(request, pk_id):
    # list single project at /projects/<pk_id>
    project = Project.objects.get(pk=pk_id)
    snapshots = Snapshot.objects.filter(project=project)
    data = {
      "id": project.pk,
      "name": project.name,
      "snapshot_ids": [snapshot.pk for snapshot in snapshots],
    }
    return HttpResponse(content=json.dumps(data), mimetype="text/json")

Reasons to avoid 'hand-writing' the code are obvious - avoid bugs from typos, code is shorter and simpler, json module is likely to be faster.

If you are concerned about the 'readability' of the generated JSON the json module provides some options for controlling the output (indents etc):
http://docs.python.org/2/library/json.html

I usually use this little function:

import json
from django.http import HttpResponse

def json_response(ob):
    return HttpResponse(
        json.dumps(ob), mimetype="application/json")

So then you can just return the result of that from a view:

def listproject(request, pk_id):
    project = Project.objects.get(pk=pk_id)  # Use get_object_or_404 ?
    snapshots = Snapshot.objects.filter(project=project)
    return json_response({
       "id": project.pk,
       "name": project.name,
       "snapshot_ids": [snapshot.pk for snapshot in snapshots],
    })
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top