mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Fixes #13252 -- Use the natural key instead of the primary key when serializing
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14994 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -170,3 +170,21 @@ class DeserializedObject(object):
|
||||
# prevent a second (possibly accidental) call to save() from saving
|
||||
# the m2m data twice.
|
||||
self.m2m_data = None
|
||||
|
||||
def build_instance(Model, data, db):
|
||||
"""
|
||||
Build a model instance.
|
||||
|
||||
If the model instance doesn't have a primary key and the model supports
|
||||
natural keys, try to retrieve it from the database.
|
||||
"""
|
||||
obj = Model(**data)
|
||||
if obj.pk is None and hasattr(Model, 'natural_key') and\
|
||||
hasattr(Model._default_manager, 'get_by_natural_key'):
|
||||
pk = obj.natural_key()
|
||||
try:
|
||||
obj.pk = Model._default_manager.db_manager(db)\
|
||||
.get_by_natural_key(*pk).pk
|
||||
except Model.DoesNotExist:
|
||||
pass
|
||||
return obj
|
||||
|
||||
@@ -27,11 +27,13 @@ class Serializer(base.Serializer):
|
||||
self._current = {}
|
||||
|
||||
def end_object(self, obj):
|
||||
self.objects.append({
|
||||
"model" : smart_unicode(obj._meta),
|
||||
"pk" : smart_unicode(obj._get_pk_val(), strings_only=True),
|
||||
"fields" : self._current
|
||||
})
|
||||
data = {
|
||||
"model": smart_unicode(obj._meta),
|
||||
"fields": self._current
|
||||
}
|
||||
if not self.use_natural_keys or not hasattr(obj, 'natural_key'):
|
||||
data['pk'] = smart_unicode(obj._get_pk_val(), strings_only=True)
|
||||
self.objects.append(data)
|
||||
self._current = None
|
||||
|
||||
def handle_field(self, obj, field):
|
||||
@@ -82,7 +84,9 @@ def Deserializer(object_list, **options):
|
||||
for d in object_list:
|
||||
# Look up the model and starting build a dict of data for it.
|
||||
Model = _get_model(d["model"])
|
||||
data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
|
||||
data = {}
|
||||
if 'pk' in d:
|
||||
data[Model._meta.pk.attname] = Model._meta.pk.to_python(d['pk'])
|
||||
m2m_data = {}
|
||||
|
||||
# Handle each field
|
||||
@@ -127,7 +131,9 @@ def Deserializer(object_list, **options):
|
||||
else:
|
||||
data[field.name] = field.to_python(field_value)
|
||||
|
||||
yield base.DeserializedObject(Model(**data), m2m_data)
|
||||
obj = base.build_instance(Model, data, db)
|
||||
|
||||
yield base.DeserializedObject(obj, m2m_data)
|
||||
|
||||
def _get_model(model_identifier):
|
||||
"""
|
||||
|
||||
@@ -42,16 +42,12 @@ class Serializer(base.Serializer):
|
||||
raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
|
||||
|
||||
self.indent(1)
|
||||
obj_pk = obj._get_pk_val()
|
||||
if obj_pk is None:
|
||||
attrs = {"model": smart_unicode(obj._meta),}
|
||||
else:
|
||||
attrs = {
|
||||
"pk": smart_unicode(obj._get_pk_val()),
|
||||
"model": smart_unicode(obj._meta),
|
||||
}
|
||||
|
||||
self.xml.startElement("object", attrs)
|
||||
object_data = {"model": smart_unicode(obj._meta)}
|
||||
if not self.use_natural_keys or not hasattr(obj, 'natural_key'):
|
||||
obj_pk = obj._get_pk_val()
|
||||
if obj_pk is not None:
|
||||
object_data['pk'] = smart_unicode(obj_pk)
|
||||
self.xml.startElement("object", object_data)
|
||||
|
||||
def end_object(self, obj):
|
||||
"""
|
||||
@@ -173,13 +169,10 @@ class Deserializer(base.Deserializer):
|
||||
Model = self._get_model_from_node(node, "model")
|
||||
|
||||
# Start building a data dictionary from the object.
|
||||
# If the node is missing the pk set it to None
|
||||
if node.hasAttribute("pk"):
|
||||
pk = node.getAttribute("pk")
|
||||
else:
|
||||
pk = None
|
||||
|
||||
data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}
|
||||
data = {}
|
||||
if node.hasAttribute('pk'):
|
||||
data[Model._meta.pk.attname] = Model._meta.pk.to_python(
|
||||
node.getAttribute('pk'))
|
||||
|
||||
# Also start building a dict of m2m data (this is saved as
|
||||
# {m2m_accessor_attribute : [list_of_related_objects]})
|
||||
@@ -210,8 +203,10 @@ class Deserializer(base.Deserializer):
|
||||
value = field.to_python(getInnerText(field_node).strip())
|
||||
data[field.name] = value
|
||||
|
||||
obj = base.build_instance(Model, data, self.db)
|
||||
|
||||
# Return a DeserializedObject so that the m2m data has a place to live.
|
||||
return base.DeserializedObject(Model(**data), m2m_data)
|
||||
return base.DeserializedObject(obj, m2m_data)
|
||||
|
||||
def _handle_fk_field_node(self, node, field):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user