Login

An alternative model serializer for django models

Author:
isaact
Posted:
November 3, 2008
Language:
Python
Version:
1.0
Score:
2 (after 2 ratings)

Django's serializer has some limitations which makes it a bit of a pain to use. Basically it will ignore any atributes that have been added to a model object.

The code below is for an alternative serializer. This version allows you select what attributes will be serialized on a per object basis. It also allows you to either serialize the data into json or xml.

The original json encoder was written by Wolfram Kriesing

Example Usage:

dumper = DataDumper()
dumper.selectObjectFields('class_name',[...fields...])
dumper.selectObjectFields('class_name',[...fields...])
dumper.dump(model_instance,'xml')
dumper.dump(model_instance,'json')
dumper.dump(queryset,'xml')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import types
from django.db import models
import pyxslt.serialize
from django.utils import simplejson as json
from django.core.serializers.json import DateTimeAwareJSONEncoder
from decimal import *

class DataDumper:
    fields = {}
    def selectObjectFields(self,objectType,fields = []):
        self.fields[objectType] = fields

    def dump(self,data,format='xml'):
        """
        The main issues with django's default json serializer is that properties that
        had been added to a object dynamically are being ignored (and it also has 
        problems with some models).
        """
    
        def _any(data):
            ret = None
            if type(data) is types.ListType:
                ret = _list(data)
            elif type(data) is types.DictType:
                ret = _dict(data)
            elif isinstance(data, Decimal):
                # json.dumps() cant handle Decimal
                ret = str(data)
            elif isinstance(data, models.query.QuerySet):
                # Actually its the same as a list ...
                ret = _list(data)
            elif isinstance(data, models.Model):
                ret = _model(data)
            else:
                ret = data
            return ret
        
        def _model(data):
            ret = {}
            # If we only have a model, we only want to encode the fields.
            objType = data.__class__.__name__
            for f in data._meta.fields:
                if (self.fields[objType]) and (f.attname in self.fields[objType]):
                    ret[f.attname] = _any(getattr(data, f.attname))
            # And additionally encode arbitrary properties that had been added.
            fields = dir(data.__class__) + ret.keys()
            add_ons = [k for k in dir(data) if k not in fields]
            for k in add_ons:
                if (self.fields[objType]) and (k in self.fields[objType]):
                    ret[k] = _any(getattr(data, k))
            return ret
        def _list(data):
            ret = []
            for v in data:
                ret.append(_any(v))
            return ret
        
        def _dict(data):
            ret = {}
            for k,v in data.items():
                ret[k] = _any(v)
            return ret
        
        ret = _any(data)
        if(format == 'xml'):
            return pyxslt.serialize.toString(prettyPrintXml=False,data=ret,)
        else:
             return json.dumps(ret, cls=DateTimeAwareJSONEncoder)

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

fredpyo (on April 28, 2009):

This was of great use, thanks! Now I have disposed my silly tiny json dumper function in favour of this more complete implementation.

#

Please login first before commenting.