Friday, 27 February 2009

Django Full Serializers - Part I

Introduction

The wadofstuff.django.serializers python module extends Django's built-in serializers, adding 3 new capabilities inspired by the Ruby on Rails JSON serializer. These parameters allow the developer more control over how their models are serialized. The additional capabilities are:
  • excludes - a list of fields to be excluded from serialization. The excludes list takes precedence over the fields argument.
  • extras - a list of non-model field properties or callables to be serialized.
  • relations - a list or dictionary of model related fields to be followed and serialized.
De/Serialization Formats

At the moment the module only supports serializing to JSON and Python. It will also only deserialize data that is in the original Django format. i.e. it won't deserialize the results of using the excludes, extras, or relations options.

Source

The source for the serialization module can be obtained here.

Examples

Project Settings

You must add the following to your project's settings.py to be able to use the JSON serializer.
SERIALIZATION_MODULES = {
'json': 'wadofstuff.django.serializers.json'
}
Backwards Compatibility

The Wad of Stuff serializers are 100% compatible with the Django serializers when serializing a model.
>>> from django.contrib.auth.models import Group
>>> from django.core import serializers
>>> print serializers.serialize('json', Group.objects.all(), indent=4)
[
{
"pk": 2,
"model": "auth.group",
"fields": {
"name": "session",
"permissions": [
19
]
}
}
]
Excludes
>>> print serializers.serialize('json', Group.objects.all(), indent=4, excludes=('permissions',))
[
{
"pk": 2,
"model": "auth.group",
"fields": {
"name": "session"
}
}
]
Extras

The extras option allows the developer to serialize properties of a model that are not fields. These properties may be almost any standard python attribute or method. The only limitation being that you may only serialize methods that do not require any arguments.

For demonstration purposes in this example I monkey patch the Group model to have a get_absolute_url() method.
>>> def get_absolute_url(self):
... return u'/group/%s' % self.name
...
>>> Group.get_absolute_url = get_absolute_url
>>> print serializers.serialize('json', Group.objects.all(), indent=4, extras=('__unicode__','get_absolute_url'))
[
{
"pk": 2,
"model": "auth.group",
"extras": {
"get_absolute_url": "/group/session",
"__unicode__": "session"
},
"fields": {
"name": "session",
"permissions": [
19
]
}
}
]
Stay tuned for the second part of this article where I demonstrate the ability to serialize related fields such as ForeignKeys and ManyToManys.

5 comments:

Malcolm said...

If this gets a bit of use and you get to the point of feeling it's really solid, it might be worth proposing as an addition to Django's built-in serialisers. Look for a "call for features" for the 1.2 release; that would be about the right timing.

I know there's been some discussion in the past about what's in and out of scope for the serialisers, but some of those decisions are worth revisiting if there's working, tested code behind the idea (and I really can't remember whether we concluded "out of scope" or "will consider if somebody does the work").

Ahik said...

Very good. Seems that the Full Serializer overcome some of the limitation of the current serializer. I was looking for something like that in one of my projects that needs those Json capabilities.
Thanks.

(Ahik)

matthew said...

Thanks Malcolm. I have a bunch of tests written for this already but they are coupled to the models in a private Django application. When I find time I'll rewrite them and commit them to the repo. I'll keep an eye out for the 1.2 call!

DV said...

These serializers made my project much easier and saved me from having to implement this myself. They're very useful. Thanks so much!

Bob said...

There's at least one ticket open on serializing extra fields: http://code.djangoproject.com/ticket/5711

You could try improving on the patch that's on there. I'd definitely be in favor of adding these features to Django's built-in serializers.

If you could also add serialization of annotate/aggregate fields, that would be great, too :)