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 |
---|