Merged the queryset-refactor branch into trunk.
[fdr-django.git] / django / core / serializers / base.py
bloba79497ecec8f5b60a8c284277bfabc35050ac4df
1 """
2 Module for abstract serializer/unserializer base classes.
3 """
5 try:
6 from cStringIO import StringIO
7 except ImportError:
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."""
14 pass
16 class DeserializationError(Exception):
17 """Something bad happened during deserialization."""
18 pass
20 class Serializer(object):
21 """
22 Abstract serializer base class.
23 """
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):
30 """
31 Serialize a queryset.
32 """
33 self.options = options
35 self.stream = options.get("stream", StringIO())
36 self.selected_fields = options.get("fields")
38 self.start_serialization()
39 for obj in queryset:
40 self.start_object(obj)
41 for field in obj._meta.fields:
42 if field.serialize:
43 if field.rel is None:
44 if self.selected_fields is None or field.attname in self.selected_fields:
45 self.handle_field(obj, field)
46 else:
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:
50 if field.serialize:
51 if self.selected_fields is None or field.attname in self.selected_fields:
52 self.handle_m2m_field(obj, field)
53 self.end_object(obj)
54 self.end_serialization()
55 return self.getvalue()
57 def get_string_value(self, obj, field):
58 """
59 Convert a field's value to a string.
60 """
61 if isinstance(field, models.DateTimeField):
62 value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S")
63 else:
64 value = field.flatten_data(follow=None, obj=obj).get(field.name, "")
65 return smart_unicode(value)
67 def start_serialization(self):
68 """
69 Called when serializing of the queryset starts.
70 """
71 raise NotImplementedError
73 def end_serialization(self):
74 """
75 Called when serializing of the queryset ends.
76 """
77 pass
79 def start_object(self, obj):
80 """
81 Called when serializing of an object starts.
82 """
83 raise NotImplementedError
85 def end_object(self, obj):
86 """
87 Called when serializing of an object ends.
88 """
89 pass
91 def handle_field(self, obj, field):
92 """
93 Called to handle each individual (non-relational) field on an object.
94 """
95 raise NotImplementedError
97 def handle_fk_field(self, obj, field):
98 """
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
109 def getvalue(self):
111 Return the fully serialized queryset (or None if the output stream is
112 not seekable).
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)
129 else:
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...)
134 models.get_apps()
136 def __iter__(self):
137 return self
139 def next(self):
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):
156 self.object = obj
157 self.m2m_data = m2m_data
159 def __repr__(self):
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
167 # methods.
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.
175 self.m2m_data = None