Login

Deep json serialization

Author:
alexey-boriskin
Posted:
July 14, 2009
Language:
Python
Version:
1.0
Score:
0 (after 0 ratings)

Custom serialization, the poor try to make something like django full serializers

Usage: you need two files, goodjson.py and goodpython.py, for example, in the root of application named "core". Then, add two lines into your settings.py:

SERIALIZATION_MODULES = {'goodjson' : 'core.goodjson',
                         'goodpython': 'core.goodpython'}

This thing does only serialization, not deserialization. You were warned.

  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
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
goodjson.py: 

from django.core.serializers.json import DateTimeAwareJSONEncoder
from django.core import serializers
from django.db.models.query import QuerySet
from django.db.models import Model
from django.utils import simplejson
from django.core.serializers.python import Serializer as PythonSerializer#, Deserializer as PythonDeserializer
from django.utils.encoding import smart_unicode
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

class ModelAwareJSONEncoder(DateTimeAwareJSONEncoder):
    
    def __init__(self,select_related=False,include_unicode=False,**options):
        super(ModelAwareJSONEncoder,self).__init__(**options)
        self.select_related = select_related
        self.include_unicode = include_unicode
        
    def default(self, o):
        
        if self.select_related:
            serializer_name = 'goodpython'
        else:
            serializer_name = 'python'
        
        if isinstance(o, QuerySet):
            serializer = serializers.get_serializer(serializer_name)()
            serializer.include_unicode = self.include_unicode
            return serializer.serialize(o)
        if isinstance(o, Model):
            serializer = serializers.get_serializer(serializer_name)()
            serializer.include_unicode = self.include_unicode
            return serializer.serialize([o])[0]
        else:
            return super(ModelAwareJSONEncoder, self).default(o)
        
class Serializer(PythonSerializer):
    def serialize(self, object, **options):
        return simplejson.dumps(object, cls=ModelAwareJSONEncoder, **options)


goodpython.py:
from django.core.serializers.json import DateTimeAwareJSONEncoder
from django.core import serializers
from django.db.models.query import QuerySet
from django.db.models import Model
from django.utils import simplejson
from django.core.serializers.python import Serializer as PythonSerializer#, Deserializer as PythonDeserializer
from django.utils.encoding import smart_unicode
from django.template.defaultfilters import force_escape, escapejs, mark_safe
from core.libs.htmlfield import HtmlField
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

        
class Serializer(PythonSerializer):
    def end_object(self, obj):
        fields = self._current
        if hasattr(self,'include_unicode') and self.include_unicode:
            fields.update({'__unicode__': unicode(obj)})
        self.objects.append({
            "model"  : smart_unicode(obj._meta),
            "pk"     : smart_unicode(obj._get_pk_val(), strings_only=True),
            "fields" : fields
        })
        self._current = None

    def handle_fk_field(self, obj, field):
        related = getattr(obj, field.name)
        self._current[field.name] = self.serialize_related(related)

    def handle_m2m_field(self, obj, field):
        self._current[field.name] =  [self.serialize_related(related) for related in getattr(obj, field.name).iterator()]
        
    def handle_field(self, obj, field):
        ''' The std. serialization is not suitable for the fields containing HTML. If such JSON is being output inside an inline <script> tag, the javascript code become invalid. This is why we need escapejs function to be applied to the contents of such fields. But after that the result is being escaped one more time. So, you need to unescape the result in your javascript with unescapejs()
        '''
        if isinstance(field, HtmlField):
            self._current[field.name] = smart_unicode(escapejs(getattr(obj, field.name) or ''), strings_only=True)
        else:
            self._current[field.name] = smart_unicode(getattr(obj, field.name), strings_only=True)

    def serialize_related(self,related):
        if hasattr(self, 'already_serialized') and related in self.already_serialized:
            serializer = serializers.get_serializer('python')()
        else:
            if hasattr(self, 'already_serialized'):
                self.already_serialized.add(related)
            else:
                self.already_serialized = set([related])
            serializer = serializers.get_serializer('goodpython')()
            serializer.already_serialized = self.already_serialized 
        value = None
        serializer.include_unicode = self.include_unicode
        if isinstance(related, QuerySet):
            value = serializer.serialize(related,**self.options)
        if isinstance(related, Model):
            value = serializer.serialize([related],**self.options)[0]
        return value

More like this

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

Comments

jtheoof (on January 7, 2011):

What is HtmlField that you are talking about line 54?

#

Please login first before commenting.