Code

Ticket #4656: python.py

File python.py, 4.8 KB (added by Matthew Flanagan <mattimustang@…>, 6 years ago)
Line 
1"""
2Full Python serializer for Django.
3"""
4import base
5from django.utils.encoding import smart_unicode
6from django.core.serializers.python import Deserializer as PythonDeserializer
7
8class Serializer(base.Serializer):
9    """
10    Python serializer for Django modelled after Ruby on Rails.
11    Default behaviour is to serialize only model fields with the exception
12    of ForeignKey and ManyToMany fields which must be explicitly added in the
13    ``relations`` argument.
14    """
15
16    def __init__(self, *args, **kwargs):
17        """
18        Initialize instance attributes.
19        """
20        self._fields = None
21        self._extras = None
22        self.objects = []
23        super(Serializer, self).__init__(*args, **kwargs)
24
25    def start_serialization(self):
26        """
27        Called when serializing of the queryset starts.
28        """
29        self._fields = None
30        self._extras = None
31        self.objects = []
32
33    def end_serialization(self):
34        """
35        Called when serializing of the queryset ends.
36        """
37        pass
38
39    def start_object(self, obj):
40        """
41        Called when serializing of an object starts.
42        """
43        self._fields = {}
44        self._extras = {}
45
46    def end_object(self, obj):
47        """
48        Called when serializing of an object ends.
49        """
50        self.objects.append({
51            "model"  : smart_unicode(obj._meta),
52            "pk"     : smart_unicode(obj._get_pk_val(), strings_only=True),
53            "fields" : self._fields
54        })
55        if self._extras:
56            self.objects[-1]["extras"] = self._extras
57        self._fields = None
58        self._extras = None
59
60    def handle_field(self, obj, field):
61        """
62        Called to handle each individual (non-relational) field on an object.
63        """
64        self._fields[field.name] = smart_unicode(getattr(obj, field.name),
65            strings_only=True)
66
67    def handle_fk_field(self, obj, field):
68        """
69        Called to handle a ForeignKey field.
70        Recursively serializes relations specified in the 'relations' option.
71        """
72        fname = field.name
73        related = getattr(obj, fname)
74        if related is not None:
75            if fname in self.relations:
76                # perform full serialization of FK
77                serializer = Serializer()
78                options = {}
79                if isinstance(self.relations, dict):
80                    if isinstance(self.relations[fname], dict):
81                        options = self.relations[fname]
82                self._fields[fname] = serializer.serialize([related],
83                    **options)[0]
84            else:
85                # emulate the original behaviour and serialize the pk value
86                if field.rel.field_name == related._meta.pk.name:
87                    # Related to remote object via primary key
88                    related = related._get_pk_val()
89                else:
90                    # Related to remote object via other field
91                    related = getattr(related, field.rel.field_name)
92                self._fields[fname] = smart_unicode(related, strings_only=True)
93        else:
94            self._fields[fname] = smart_unicode(related, strings_only=True)
95
96    def handle_m2m_field(self, obj, field):
97        """
98        Called to handle a ManyToManyField.
99        Recursively serializes relations specified in the 'relations' option.
100        """
101        fname = field.name
102        if fname in self.relations:
103            # perform full serialization of M2M
104            serializer = Serializer()
105            options = {}
106            if isinstance(self.relations, dict):
107                if isinstance(self.relations[fname], dict):
108                    options = self.relations[fname]
109            self._fields[fname] = [
110                serializer.serialize([related], **options)[0]
111                   for related in getattr(obj, fname).iterator()]
112        else:
113            # emulate the original behaviour and serialize to a list of
114            # primary key values
115            self._fields[fname] = [
116                smart_unicode(related._get_pk_val(), strings_only=True)
117                   for related in getattr(obj, fname).iterator()]
118
119
120    def getvalue(self):
121        """
122        Return the fully serialized queryset (or None if the output stream is
123        not seekable).
124        """
125        return self.objects
126   
127    def handle_extra_field(self, obj, field):
128        """
129        Return "extra" fields that the user specifies.
130        Can be a property or callable that takes no arguments.
131        """
132        if hasattr(obj, field):
133            extra = getattr(obj, field)
134            if callable(extra):
135                self._extras[field] = smart_unicode(extra(), strings_only=True)
136            else:
137                self._extras[field] = smart_unicode(extra, strings_only=True)
138               
139
140Deserializer = PythonDeserializer