Django

Code

root/django/trunk/django/core/serializers/python.py

Revision 8676, 3.8 kB (checked in by jacob, 4 months ago)

Fixed #8651: correctly deserialize objects with 0 for pk/fk.

  • Property svn:eol-style set to native
Line 
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             "fields" : self._current
34         })
35         self._current = None
36
37     def handle_field(self, obj, field):
38         self._current[field.name] = smart_unicode(getattr(obj, field.name), strings_only=True)
39
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)
50
51     def handle_m2m_field(self, obj, field):
52         if field.creates_table:
53             self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
54                                for related in getattr(obj, field.name).iterator()]
55
56     def getvalue(self):
57         return self.objects
58
59 def Deserializer(object_list, **options):
60     """
61     Deserialize simple Python objects back into Django ORM instances.
62
63     It's expected that you pass the Python objects themselves (instead of a
64     stream or a string) to the constructor
65     """
66     models.get_apps()
67     for d in object_list:
68         # Look up the model and starting build a dict of data for it.
69         Model = _get_model(d["model"])
70         data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
71         m2m_data = {}
72
73         # Handle each field
74         for (field_name, field_value) in d["fields"].iteritems():
75             if isinstance(field_value, str):
76                 field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
77
78             field = Model._meta.get_field(field_name)
79
80             # Handle M2M relations
81             if field.rel and isinstance(field.rel, models.ManyToManyRel):
82                 m2m_convert = field.rel.to._meta.pk.to_python
83                 m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
84
85             # Handle FK fields
86             elif field.rel and isinstance(field.rel, models.ManyToOneRel):
87                 if field_value is not None:
88                     data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
89                 else:
90                     data[field.attname] = None
91
92             # Handle all other fields
93             else:
94                 data[field.name] = field.to_python(field_value)
95
96         yield base.DeserializedObject(Model(**data), m2m_data)
97
98 def _get_model(model_identifier):
99     """
100     Helper to look up a model from an "app_label.module_name" string.
101     """
102     try:
103         Model = models.get_model(*model_identifier.split("."))
104     except TypeError:
105         Model = None
106     if Model is None:
107         raise base.DeserializationError(u"Invalid model identifier: '%s'" % model_identifier)
108     return Model
Note: See TracBrowser for help on using the browser.