Python Programming, news on the Voidspace Python Projects and all things techie.

Django json support

emoticon:noise As I mentioned in my last entry I'm now working on a Silverlight application with Django on the backend. This means that we're using Django to serve json to the Silverlight application, so whilst we're using the Django ORM, url routing and authentication we aren't using its templating.

The data model is 'unusual' but makes sense for the app. We've only implemented the first user story, which uses a subset of the data, but you can already start to see the shape of it. Here's a simplified approximation of the data from the point of view of the Django model classes:

from django.db import models

class CompanyType(models.Model):
    type = models.CharField(max_length=255)

class Company(models.Model):
    name = models.CharField(max_length=255)
    company_type = models.ForeignKey(CompanyType)

class Address(models.Model):
    street = models.CharField(max_length=255)
    city = models.CharField(max_length=255)
    postcode = models.CharField(max_length=255)
    company = models.ForeignKey(Company)

class Individual(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    address = models.ForeignKey(Address)

The reason for this slightly non-intuitive setup is that a company may have several addresses. At every address there can be several contacts.

In our view we have a companies function that needs to return a list of all the companies. If we use the built-in json serializer then for the company_type field it just puts an id number into the json. If we wanted the actual company_type then we would have to make an additional query per company.

Additionally, for this view we want to retrieve all of the addresses associated with a company and every individual associated with each address.

There is a project called wadostuff that includes a replacement serializer. It's very easy to use, just specify the following in settings.py:

SERIALIZATION_MODULES = {
    #'json': 'djangoserializers.json'
    'json': 'wadofstuff.django.serializers.json'
}

When we import and call the Django json serializer we can now specify relations for the serializer to follow and include in the json:

from django.core import serializers
from project.app.models import Company

from django.http import HttpResponse

def company(request):
    companies = Company.objects.all()
    json = serializers.serialize(companies, relations=('company_type',))
    return HttpResponse(json, mimetype="application/json"))

This doesn't solve the problem of how we include the addresses and individuals information. One option would be to generate three separate lists and include them all in the json and let the client sort them out. The wadostuff serializer does let us specify a set of extra fields (extras). Despite what the documentation says, in practise I had to implement these as methods on the model objects that could only return a string. This means I couldn't use it to return a list of model objects like I wanted.

Maybe I'm missing something obvious, which is entirely likely as I'm new to Django, but it doesn't seem like this use case is that unusual. I'm surprised that Django has no infrastructure at all to support this kind of use case??

After a bit of hunting I discovered the awesome django-piston project. We don't need an XML or YAML API, nor streaming or throttling, but it includes an awesome json serializer that I 'borrowed' and hacked around so that I could use it on its own. My final code for associating each company with the related addresses and individuals looks like this:

from project.app.models import Company
from project.modules.emitter import Emitter

from django.http import HttpResponse


def companies(request):
    companies = Company.objects.all()

    for company in companies:
        addresses = company.address_set.all()
        company.addresses = addresses
        for address in addresses:
            individuals = address.individual_set.all()
            address.individuals = individuals

    emitter = Emitter(fields=('company', 'company_type', 'address', 'addresses', 'individuals'))
    thejson = emitter.render(companies)
    return HttpResponse(thejson, mimetype="application/json")

This follows the 'company', 'company_type', and 'address' relations on model objects it serializes and also handles the addresses and individuals fields. What I get back on the Silverlight end is json representing a list of all companies. Each company has an 'addresses' field with a list of all addresses for that company and each address has an 'individuals' field. This is exactly what we need.

Note

In the comments Doug Napoleone suggests using select_related() rather than all() as it should be more efficient given the way we are using all the relations.

Doug also suggests setting 'related_name' in the model fields which would give me nicer names than address_set and individual_set. If I taught the serializer how to handle these names then I could move the loop from my view to the serializer; but the loop would still be there, so no efficiency gain just nicer looking code. Smile

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2009-11-16 01:54:10 | |

Categories: , , Tags: , ,


New Job with Django and IronPython

emoticon:men Big personal news; I've changed jobs. After more than three years working with Resolver Systems I felt it was time to broaden my development experience. I greatly enjoyed working with Resolver Systems and learned an enormous amount; I'm sorry to leave them but I'm sure they'll manage to cope without me. Smile

I'm now freelance, starting with a contract with a web development firm based in Germany called Comsulting. I first came into contact with Comsulting earlier this year through their lead developer Sven Passig. One of their big customers wanted a web application with the front-end written in IronPython and Silverlight. I did some consulting for them on this as it was their first Silverlight application.

You can hear a bit about what they've been up to with IronPython and Silverlight on the Python 411 podcast that Sven recorded with Ron Jeffries:

I've just been onsite in Germany with them for two weeks but will mainly be working from home. Comsulting's biggest customers are within the German and Swiss media industry and they have several applications for tracking and organising advertising in magazines and websites. It turns out that these media companies really like Silverlight...

We're developing web applications for these companies and after working on the tail end of one project for the first week I started a new project with Stepan Mitt, a designer / developer who also contracts for Comsulting and who happens to be a really cool guy. We're using Django on the server (with CPython 2.5 on Linux) and Silverlight on the client side. I'm converting the Comsulting guys to Test Driven Development, but we still need to investigate the best way to functionally test Silverlight applications.

It's great to be working with CPython again, and especially with Django, but also great to be able to use my IronPython experience. Our Silverlight application communicates with Django via json, so we're using the Django ORM and authentication but our views generate json. I'm sure there will be a blog entry or two out of this.

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2009-11-14 20:22:38 | |

Categories: , , , Tags: ,


Hosted by Webfaction

Counter...