1 | """
|
---|
2 | Full Python serializer for Django.
|
---|
3 | """
|
---|
4 | import base
|
---|
5 | from django.utils.encoding import smart_unicode
|
---|
6 | from django.core.serializers.python import Deserializer as PythonDeserializer
|
---|
7 |
|
---|
8 | class 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 |
|
---|
140 | Deserializer = PythonDeserializer
|
---|