1 | """
|
---|
2 | A Python "serializer". Doesn't do much serializing per se -- just converts to
|
---|
3 | and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for
|
---|
4 | other serializers.
|
---|
5 | """
|
---|
6 |
|
---|
7 | from django.conf import settings
|
---|
8 | from django.core.serializers import base
|
---|
9 | from django.db import models
|
---|
10 | from django.utils.encoding import smart_unicode
|
---|
11 |
|
---|
12 | class Serializer(base.Serializer):
|
---|
13 | """
|
---|
14 | Serializes a QuerySet to basic Python objects.
|
---|
15 | """
|
---|
16 |
|
---|
17 | internal_use_only = True
|
---|
18 |
|
---|
19 | def start_serialization(self):
|
---|
20 | self._current = None
|
---|
21 | self.objects = []
|
---|
22 |
|
---|
23 | def end_serialization(self):
|
---|
24 | pass
|
---|
25 |
|
---|
26 | def start_object(self, obj):
|
---|
27 | self._current = {}
|
---|
28 |
|
---|
29 | def end_object(self, obj):
|
---|
30 | self.objects.append({
|
---|
31 | "model" : smart_unicode(obj._meta),
|
---|
32 | "pk" : smart_unicode(obj._get_pk_val(), strings_only=True),
|
---|
33 | "name" : smart_unicode(obj._meta.pk.name),
|
---|
34 | "fields" : self._current
|
---|
35 | })
|
---|
36 | self._current = None
|
---|
37 |
|
---|
38 | def handle_field(self, obj, field):
|
---|
39 | self._current[field.name] = smart_unicode(getattr(obj, field.name), strings_only=True)
|
---|
40 |
|
---|
41 | def handle_fk_field(self, obj, field):
|
---|
42 | related = getattr(obj, field.name)
|
---|
43 | if related is not None:
|
---|
44 | if field.rel.field_name == related._meta.pk.name:
|
---|
45 | # Related to remote object via primary key
|
---|
46 | related = related._get_pk_val()
|
---|
47 | else:
|
---|
48 | # Related to remote object via other field
|
---|
49 | related = getattr(related, field.rel.field_name)
|
---|
50 | self._current[field.name] = smart_unicode(related, strings_only=True)
|
---|
51 |
|
---|
52 | def handle_m2m_field(self, obj, field):
|
---|
53 | if field.creates_table:
|
---|
54 | self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
|
---|
55 | for related in getattr(obj, field.name).iterator()]
|
---|
56 |
|
---|
57 | def getvalue(self):
|
---|
58 | return self.objects
|
---|
59 |
|
---|
60 | def Deserializer(object_list, **options):
|
---|
61 | """
|
---|
62 | Deserialize simple Python objects back into Django ORM instances.
|
---|
63 |
|
---|
64 | It's expected that you pass the Python objects themselves (instead of a
|
---|
65 | stream or a string) to the constructor
|
---|
66 | """
|
---|
67 | models.get_apps()
|
---|
68 | for d in object_list:
|
---|
69 | # Look up the model and starting build a dict of data for it.
|
---|
70 | Model = _get_model(d["model"])
|
---|
71 | data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
|
---|
72 | m2m_data = {}
|
---|
73 |
|
---|
74 | # Handle each field
|
---|
75 | for (field_name, field_value) in d["fields"].iteritems():
|
---|
76 | if isinstance(field_value, str):
|
---|
77 | field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
|
---|
78 |
|
---|
79 | field = Model._meta.get_field(field_name)
|
---|
80 |
|
---|
81 | # Handle M2M relations
|
---|
82 | if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
---|
83 | m2m_convert = field.rel.to._meta.pk.to_python
|
---|
84 | m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
|
---|
85 |
|
---|
86 | # Handle FK fields
|
---|
87 | elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
---|
88 | if field_value is not None:
|
---|
89 | data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
|
---|
90 | else:
|
---|
91 | data[field.attname] = None
|
---|
92 |
|
---|
93 | # Handle all other fields
|
---|
94 | else:
|
---|
95 | data[field.name] = field.to_python(field_value)
|
---|
96 |
|
---|
97 | yield base.DeserializedObject(Model(**data), m2m_data)
|
---|
98 |
|
---|
99 | def _get_model(model_identifier):
|
---|
100 | """
|
---|
101 | Helper to look up a model from an "app_label.module_name" string.
|
---|
102 | """
|
---|
103 | try:
|
---|
104 | Model = models.get_model(*model_identifier.split("."))
|
---|
105 | except TypeError:
|
---|
106 | Model = None
|
---|
107 | if Model is None:
|
---|
108 | raise base.DeserializationError(u"Invalid model identifier: '%s'" % model_identifier)
|
---|
109 | return Model
|
---|