2 Module for abstract serializer/unserializer base classes.
6 from cStringIO
import StringIO
8 from StringIO
import StringIO
9 from django
.db
import models
10 from django
.utils
.encoding
import smart_str
, smart_unicode
12 class SerializationError(Exception):
13 """Something bad happened during serialization."""
16 class DeserializationError(Exception):
17 """Something bad happened during deserialization."""
20 class Serializer(object):
22 Abstract serializer base class.
25 # Indicates if the implemented serializer is only available for
26 # internal Django use.
27 internal_use_only
= False
29 def serialize(self
, queryset
, **options
):
33 self
.options
= options
35 self
.stream
= options
.get("stream", StringIO())
36 self
.selected_fields
= options
.get("fields")
38 self
.start_serialization()
40 self
.start_object(obj
)
41 for field
in obj
._meta
.fields
:
44 if self
.selected_fields
is None or field
.attname
in self
.selected_fields
:
45 self
.handle_field(obj
, field
)
47 if self
.selected_fields
is None or field
.attname
[:-3] in self
.selected_fields
:
48 self
.handle_fk_field(obj
, field
)
49 for field
in obj
._meta
.many_to_many
:
51 if self
.selected_fields
is None or field
.attname
in self
.selected_fields
:
52 self
.handle_m2m_field(obj
, field
)
54 self
.end_serialization()
55 return self
.getvalue()
57 def get_string_value(self
, obj
, field
):
59 Convert a field's value to a string.
61 if isinstance(field
, models
.DateTimeField
):
62 value
= getattr(obj
, field
.name
).strftime("%Y-%m-%d %H:%M:%S")
64 value
= field
.flatten_data(follow
=None, obj
=obj
).get(field
.name
, "")
65 return smart_unicode(value
)
67 def start_serialization(self
):
69 Called when serializing of the queryset starts.
71 raise NotImplementedError
73 def end_serialization(self
):
75 Called when serializing of the queryset ends.
79 def start_object(self
, obj
):
81 Called when serializing of an object starts.
83 raise NotImplementedError
85 def end_object(self
, obj
):
87 Called when serializing of an object ends.
91 def handle_field(self
, obj
, field
):
93 Called to handle each individual (non-relational) field on an object.
95 raise NotImplementedError
97 def handle_fk_field(self
, obj
, field
):
99 Called to handle a ForeignKey field.
101 raise NotImplementedError
103 def handle_m2m_field(self
, obj
, field
):
105 Called to handle a ManyToManyField.
107 raise NotImplementedError
111 Return the fully serialized queryset (or None if the output stream is
114 if callable(getattr(self
.stream
, 'getvalue', None)):
115 return self
.stream
.getvalue()
117 class Deserializer(object):
119 Abstract base deserializer class.
122 def __init__(self
, stream_or_string
, **options
):
124 Init this serializer given a stream or a string
126 self
.options
= options
127 if isinstance(stream_or_string
, basestring
):
128 self
.stream
= StringIO(stream_or_string
)
130 self
.stream
= stream_or_string
131 # hack to make sure that the models have all been loaded before
132 # deserialization starts (otherwise subclass calls to get_model()
133 # and friends might fail...)
140 """Iteration iterface -- return the next item in the stream"""
141 raise NotImplementedError
143 class DeserializedObject(object):
145 A deserialized model.
147 Basically a container for holding the pre-saved deserialized data along
148 with the many-to-many data saved with the object.
150 Call ``save()`` to save the object (with the many-to-many data) to the
151 database; call ``save(save_m2m=False)`` to save just the object fields
152 (and not touch the many-to-many stuff.)
155 def __init__(self
, obj
, m2m_data
=None):
157 self
.m2m_data
= m2m_data
160 return "<DeserializedObject: %s>" % smart_str(self
.object)
162 def save(self
, save_m2m
=True):
163 # Call save on the Model baseclass directly. This bypasses any
164 # model-defined save. The save is also forced to be raw.
165 # This ensures that the data that is deserialized is literally
166 # what came from the file, not post-processed by pre_save/save
168 models
.Model
.save_base(self
.object, raw
=True)
169 if self
.m2m_data
and save_m2m
:
170 for accessor_name
, object_list
in self
.m2m_data
.items():
171 setattr(self
.object, accessor_name
, object_list
)
173 # prevent a second (possibly accidental) call to save() from saving
174 # the m2m data twice.