Ticket #2650: base.py

File base.py, 4.7 KB (added by ben.khoo@…, 18 years ago)

A potential patch

Line 
1"""
2Module for abstract serializer/unserializer base classes.
3"""
4
5try:
6 from cStringIO import StringIO
7except ImportError:
8 from StringIO import StringIO
9from django.db import models
10
11class SerializationError(Exception):
12 """Something bad happened during serialization."""
13 pass
14
15class DeserializationError(Exception):
16 """Something bad happened during deserialization."""
17 pass
18
19class Serializer(object):
20 """
21 Abstract serializer base class.
22 """
23
24 def serialize(self, queryset, **options):
25 """
26 Serialize a queryset.
27 """
28 self.options = options
29
30 self.stream = options.get("stream", StringIO())
31
32 self.start_serialization()
33 for obj in queryset:
34 self.start_object(obj)
35 for field in obj._meta.fields:
36 if field is obj._meta.pk:
37 continue
38 elif field.rel is None:
39 self.handle_field(obj, field)
40 else:
41 self.handle_fk_field(obj, field)
42 for field in obj._meta.many_to_many:
43 self.handle_m2m_field(obj, field)
44 self.end_object(obj)
45 self.end_serialization()
46 return self.getvalue()
47
48 def get_string_value(self, obj, field):
49 """
50 Convert a field's value to a string.
51 """
52 if isinstance(field, models.DateTimeField):
53 value = getattr(obj, field.name)
54 if value is None:
55 value = ''
56 else:
57 value = value.strftime("%Y-%m-%d %H:%M:%S")
58 elif isinstance(field, models.FileField):
59 value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
60 else:
61 value = field.flatten_data(follow=None, obj=obj).get(field.name, "")
62
63 if value is not None:
64 return str(value)
65 else:
66 return None
67
68 def start_serialization(self):
69 """
70 Called when serializing of the queryset starts.
71 """
72 raise NotImplementedError
73
74 def end_serialization(self):
75 """
76 Called when serializing of the queryset ends.
77 """
78 pass
79
80 def start_object(self, obj):
81 """
82 Called when serializing of an object starts.
83 """
84 raise NotImplementedError
85
86 def end_object(self, obj):
87 """
88 Called when serializing of an object ends.
89 """
90 pass
91
92 def handle_field(self, obj, field):
93 """
94 Called to handle each individual (non-relational) field on an object.
95 """
96 raise NotImplementedError
97
98 def handle_fk_field(self, obj, field):
99 """
100 Called to handle a ForeignKey field.
101 """
102 raise NotImplementedError
103
104 def handle_m2m_field(self, obj, field):
105 """
106 Called to handle a ManyToManyField.
107 """
108 raise NotImplementedError
109
110 def getvalue(self):
111 """
112 Return the fully serialized queryset.
113 """
114 return self.stream.getvalue()
115
116class Deserializer(object):
117 """
118 Abstract base deserializer class.
119 """
120
121 def __init__(self, stream_or_string, **options):
122 """
123 Init this serializer given a stream or a string
124 """
125 self.options = options
126 if isinstance(stream_or_string, basestring):
127 self.stream = StringIO(stream_or_string)
128 else:
129 self.stream = stream_or_string
130 # hack to make sure that the models have all been loaded before
131 # deserialization starts (otherwise subclass calls to get_model()
132 # and friends might fail...)
133 models.get_apps()
134
135 def __iter__(self):
136 return self
137
138 def next(self):
139 """Iteration iterface -- return the next item in the stream"""
140 raise NotImplementedError
141
142class DeserializedObject(object):
143 """
144 A deserialzed model.
145
146 Basically a container for holding the pre-saved deserialized data along
147 with the many-to-many data saved with the object.
148
149 Call ``save()`` to save the object (with the many-to-many data) to the
150 database; call ``save(save_m2m=False)`` to save just the object fields
151 (and not touch the many-to-many stuff.)
152 """
153
154 def __init__(self, obj, m2m_data=None):
155 self.object = obj
156 self.m2m_data = m2m_data
157
158 def __repr__(self):
159 return "<DeserializedObject: %s>" % str(self.object)
160
161 def save(self, save_m2m=True):
162 self.object.save()
163 if self.m2m_data and save_m2m:
164 for accessor_name, object_list in self.m2m_data.items():
165 setattr(self.object, accessor_name, object_list)
166
167 # prevent a second (possibly accidental) call to save() from saving
168 # the m2m data twice.
169 self.m2m_data = None
Back to Top