Merged the queryset-refactor branch into trunk.
[fdr-django.git] / django / core / serializers / python.py
blobcedab06be9cfd77fc1e62ab232190aa703e64092
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 """
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
12 class Serializer(base.Serializer):
13 """
14 Serializes a QuerySet to basic Python objects.
15 """
17 internal_use_only = True
19 def start_serialization(self):
20 self._current = None
21 self.objects = []
23 def end_serialization(self):
24 pass
26 def start_object(self, obj):
27 self._current = {}
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 "fields" : self._current
35 self._current = None
37 def handle_field(self, obj, field):
38 self._current[field.name] = smart_unicode(getattr(obj, field.name), strings_only=True)
40 def handle_fk_field(self, obj, field):
41 related = getattr(obj, field.name)
42 if related is not None:
43 if field.rel.field_name == related._meta.pk.name:
44 # Related to remote object via primary key
45 related = related._get_pk_val()
46 else:
47 # Related to remote object via other field
48 related = getattr(related, field.rel.field_name)
49 self._current[field.name] = smart_unicode(related, strings_only=True)
51 def handle_m2m_field(self, obj, field):
52 self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
53 for related in getattr(obj, field.name).iterator()]
55 def getvalue(self):
56 return self.objects
58 def Deserializer(object_list, **options):
59 """
60 Deserialize simple Python objects back into Django ORM instances.
62 It's expected that you pass the Python objects themselves (instead of a
63 stream or a string) to the constructor
64 """
65 models.get_apps()
66 for d in object_list:
67 # Look up the model and starting build a dict of data for it.
68 Model = _get_model(d["model"])
69 data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
70 m2m_data = {}
72 # Handle each field
73 for (field_name, field_value) in d["fields"].iteritems():
74 if isinstance(field_value, str):
75 field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
77 field = Model._meta.get_field(field_name)
79 # Handle M2M relations
80 if field.rel and isinstance(field.rel, models.ManyToManyRel):
81 m2m_convert = field.rel.to._meta.pk.to_python
82 m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
84 # Handle FK fields
85 elif field.rel and isinstance(field.rel, models.ManyToOneRel):
86 if field_value:
87 data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
88 else:
89 data[field.attname] = None
91 # Handle all other fields
92 else:
93 data[field.name] = field.to_python(field_value)
95 yield base.DeserializedObject(Model(**data), m2m_data)
97 def _get_model(model_identifier):
98 """
99 Helper to look up a model from an "app_label.module_name" string.
101 try:
102 Model = models.get_model(*model_identifier.split("."))
103 except TypeError:
104 Model = None
105 if Model is None:
106 raise base.DeserializationError(u"Invalid model identifier: '%s'" % model_identifier)
107 return Model