views:

99

answers:

2

Is there a way to have any @property definitions passed through to a json serializer when serializing a Django model class?

example:

class FooBar(object.Model)

name = models.CharField(...)

@property
def foo(self):
    return "My name is %s" %self.name

Want to serialize to:

[{

'name' : 'Test User',

'foo' : 'My name is Test User',

},]

A: 

You can get all of the properties of a class using some black magic:

def list_class_properties(cls):
    return [k for k,v in cls.__dict__.iteritems() if type(v) is property]

For example:

>>> class Foo:
       @property
       def bar(self):
           return "bar"

>>> list_class_properties(Foo)
['bar']

Then you can build the dictionary and serialize it from there.

Daniel DiPaolo
That would require essentially creating my own hash, only to serialize to essentially a hash. If I go that route, I can almost cut out the whole serialization. I was hoping to continue to use the django Model class and simply call serialize('json', my_object, ...)
ashchristopher
Unfortunately, it appears that Django's core serialization routines specifically exclude anything that isn't in `_meta` which basically only looks for db model fields. So while you can write up a function that pulls out only property fields (which may be better done with the `inspect.getmembers` method at second blush), even using the `fields` parameter on the `serializers.serialize` method wouldn't work.See here, where they iterate over the queryset passed in and only look for stuff in `_meta`: http://code.djangoproject.com/browser/django/trunk/django/core/serializers/base.py#L39
Daniel DiPaolo
+2  A: 

You can extend Django's serializers without /too/ much work. Here's a custom serializer that takes a queryset and a list of attributes (fields or not), and returns JSON.

from StringIO import StringIO
from django.core.serializers.json import Serializer

class MySerializer(Serializer):
    def serialize(self, queryset, list_of_attributes, **options):
        self.options = options
        self.stream = options.get("stream", StringIO())
        self.start_serialization()
        for obj in queryset:
            self.start_object(obj)
            for field in list_of_attributes:
                self.handle_field(obj, field)
            self.end_object(obj)
        self.end_serialization()
        return self.getvalue()

    def handle_field(self, obj, field):
        self._current[field] = getattr(obj, field)

Usage:

>>> MySerializer().serialize(MyModel.objects.all(), ["field1", "property2", ...])

Of course, this is probably more work than just writing your own simpler JSON serializer, but maybe not more work than your own XML serializer (you'd have to redefine "handle_field" to match the XML case in addition to changing the base class to do that).