Added various fixes to serializer implementations. Fixes mostly deal with handling nulls, non-integer primary key values (e.g., OneToOne fields or strings), and reconstruction of primary key references in related fields.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4718 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
400ee02661
commit
375c3edf6e
|
@ -54,11 +54,7 @@ class Serializer(object):
|
||||||
Convert a field's value to a string.
|
Convert a field's value to a string.
|
||||||
"""
|
"""
|
||||||
if isinstance(field, models.DateTimeField):
|
if isinstance(field, models.DateTimeField):
|
||||||
value = getattr(obj, field.name)
|
value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
if value is None:
|
|
||||||
value = ''
|
|
||||||
else:
|
|
||||||
value = value.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
elif isinstance(field, models.FileField):
|
elif isinstance(field, models.FileField):
|
||||||
value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
|
value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -57,7 +57,7 @@ def Deserializer(object_list, **options):
|
||||||
for d in object_list:
|
for d in object_list:
|
||||||
# Look up the model and starting build a dict of data for it.
|
# Look up the model and starting build a dict of data for it.
|
||||||
Model = _get_model(d["model"])
|
Model = _get_model(d["model"])
|
||||||
data = {Model._meta.pk.attname : d["pk"]}
|
data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
|
||||||
m2m_data = {}
|
m2m_data = {}
|
||||||
|
|
||||||
# Handle each field
|
# Handle each field
|
||||||
|
@ -70,16 +70,17 @@ def Deserializer(object_list, **options):
|
||||||
# Handle M2M relations
|
# Handle M2M relations
|
||||||
if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
||||||
pks = []
|
pks = []
|
||||||
|
m2m_convert = field.rel.to._meta.pk.to_python
|
||||||
for pk in field_value:
|
for pk in field_value:
|
||||||
if isinstance(pk, unicode):
|
if isinstance(pk, unicode):
|
||||||
pks.append(pk.encode(options.get("encoding", settings.DEFAULT_CHARSET)))
|
pks.append(m2m_convert(pk.encode(options.get("encoding", settings.DEFAULT_CHARSET))))
|
||||||
else:
|
else:
|
||||||
pks.append(pk)
|
pks.append(m2m_convert(pk))
|
||||||
m2m_data[field.name] = pks
|
m2m_data[field.name] = pks
|
||||||
|
|
||||||
# Handle FK fields
|
# Handle FK fields
|
||||||
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
||||||
data[field.attname] = field_value
|
data[field.attname] = field.rel.to._meta.pk.to_python(field_value)
|
||||||
|
|
||||||
# Handle all other fields
|
# Handle all other fields
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -57,10 +57,12 @@ class Serializer(base.Serializer):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Get a "string version" of the object's data (this is handled by the
|
# Get a "string version" of the object's data (this is handled by the
|
||||||
# serializer base class). None is handled specially.
|
# serializer base class).
|
||||||
|
if getattr(obj, field.name) is not None:
|
||||||
value = self.get_string_value(obj, field)
|
value = self.get_string_value(obj, field)
|
||||||
if value is not None:
|
|
||||||
self.xml.characters(str(value))
|
self.xml.characters(str(value))
|
||||||
|
else:
|
||||||
|
self.xml.addQuickElement("None")
|
||||||
|
|
||||||
self.xml.endElement("field")
|
self.xml.endElement("field")
|
||||||
|
|
||||||
|
@ -127,7 +129,8 @@ class Deserializer(base.Deserializer):
|
||||||
pk = node.getAttribute("pk")
|
pk = node.getAttribute("pk")
|
||||||
if not pk:
|
if not pk:
|
||||||
raise base.DeserializationError("<object> node is missing the 'pk' attribute")
|
raise base.DeserializationError("<object> node is missing the 'pk' attribute")
|
||||||
data = {Model._meta.pk.name : pk}
|
|
||||||
|
data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}
|
||||||
|
|
||||||
# Also start building a dict of m2m data (this is saved as
|
# Also start building a dict of m2m data (this is saved as
|
||||||
# {m2m_accessor_attribute : [list_of_related_objects]})
|
# {m2m_accessor_attribute : [list_of_related_objects]})
|
||||||
|
@ -148,9 +151,12 @@ class Deserializer(base.Deserializer):
|
||||||
|
|
||||||
# As is usually the case, relation fields get the special treatment.
|
# As is usually the case, relation fields get the special treatment.
|
||||||
if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
||||||
m2m_data[field.name] = self._handle_m2m_field_node(field_node)
|
m2m_data[field.name] = self._handle_m2m_field_node(field_node, field)
|
||||||
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
||||||
data[field.attname] = self._handle_fk_field_node(field_node)
|
data[field.attname] = self._handle_fk_field_node(field_node, field)
|
||||||
|
else:
|
||||||
|
if len(field_node.childNodes) == 1 and field_node.childNodes[0].nodeName == 'None':
|
||||||
|
value = None
|
||||||
else:
|
else:
|
||||||
value = field.to_python(getInnerText(field_node).strip().encode(self.encoding))
|
value = field.to_python(getInnerText(field_node).strip().encode(self.encoding))
|
||||||
data[field.name] = value
|
data[field.name] = value
|
||||||
|
@ -158,7 +164,7 @@ class Deserializer(base.Deserializer):
|
||||||
# Return a DeserializedObject so that the m2m data has a place to live.
|
# Return a DeserializedObject so that the m2m data has a place to live.
|
||||||
return base.DeserializedObject(Model(**data), m2m_data)
|
return base.DeserializedObject(Model(**data), m2m_data)
|
||||||
|
|
||||||
def _handle_fk_field_node(self, node):
|
def _handle_fk_field_node(self, node, field):
|
||||||
"""
|
"""
|
||||||
Handle a <field> node for a ForeignKey
|
Handle a <field> node for a ForeignKey
|
||||||
"""
|
"""
|
||||||
|
@ -166,13 +172,16 @@ class Deserializer(base.Deserializer):
|
||||||
if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None':
|
if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None':
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return getInnerText(node).strip().encode(self.encoding)
|
return field.rel.to._meta.pk.to_python(
|
||||||
|
getInnerText(node).strip().encode(self.encoding))
|
||||||
|
|
||||||
def _handle_m2m_field_node(self, node):
|
def _handle_m2m_field_node(self, node, field):
|
||||||
"""
|
"""
|
||||||
Handle a <field> node for a ManyToManyField
|
Handle a <field> node for a ManyToManyField
|
||||||
"""
|
"""
|
||||||
return [c.getAttribute("pk").encode(self.encoding) for c in node.getElementsByTagName("object")]
|
return [field.rel.to._meta.pk.to_python(
|
||||||
|
c.getAttribute("pk").encode(self.encoding))
|
||||||
|
for c in node.getElementsByTagName("object")]
|
||||||
|
|
||||||
def _get_model_from_node(self, node, attr):
|
def _get_model_from_node(self, node, attr):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue