Django模型反序列化与空PK

时间:2009-07-16 01:16:00

标签: django serialization

我已经将我的django模型序列化了:

serializers.serialize(MyModel.objects.filter(color="Red"))

得到了这个输出:

<object model="example.example" pk="133">
    <field name="name" type="CharField">John Smith</field>
    <field name="color" type="CharField">Red</field>
    ... #more fields
</object>

所以你可以看到我有pk =“133”:

现在我想再次将它反序列化为django模型并将()保存到数据库中,但是使用不同的pk,所以它应该创建具有新id的新记录。

我正在尝试解析XML并使用以下命令更改pk:

  • pk =“” - 解析器抱怨pk应该是整数
  • pk =“ - 1”或“0” - 实际创建id / pk =“1”或“0”的记录
  • pk =“None”或None或“null” - 解析器抱怨pk应为整数
  • 删除“pk”属性 - 解析器抱怨该属性是必需的

在Django Serialization文章中,有一个示例如何使用null“pk”从JSON反序列化。

# You can easily create new objects by deserializing data with an empty PK
# (It's easier to demo this with JSON...)
>>> new_author_json = '[{"pk": null, "model": "serializers.author", "fields": {"name": "Bill"}}]'
>>> for obj in serializers.deserialize("json", new_author_json):
...     obj.save()

(实际上是0.96,但我认为它应该适用于1. *)

因此在JSON中,pk可以为null,但在XML中它会抱怨。如何为XML设置pk为null?

由于

1 个答案:

答案 0 :(得分:5)

看起来像Django中的bug。无法为XML序列化对象提供空(或null / None)“pk”。

来自django / core / serializers / xml_serializer.py:

class Deserializer(base.Deserializer):
    ...
    def _handle_object(self, node):
    ...
        pk = node.getAttribute("pk")
        if not pk:
            raise base.DeserializationError("<object> node is missing the 'pk' attribute")

        data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}
    ...

如果缺少pk属性,则引发异常。所以我们必须提供一些pk。

来自django / models / fields / init .py

class AutoField(Field):
    ...
    def to_python(self, value):
        if value is None:
            return value
        try:
            return int(value)
        except (TypeError, ValueError):
            raise exceptions.ValidationError(
                _("This value must be an integer."))
    ...

如果pk不是整数 - 也是例外。

看起来没有办法提供空的pk。

解决方法可能是:

  1. 从MyModel获取最大ID
  2. id + = 1
  3. 在我的xml中使用新ID
  4. 设置“pk”
  5. 反序列化为模型
  6. 保存()
  7. 这有点棘手,因为在步骤1-5中,表应该被锁定..不知怎的......只是为了避免id碰撞。

    修改

    解决方法是:

    1. 设置pk =“999999”(某个临时整数值)
    2. 在迭代过程中,将id和pk设置为None,稍后再设置save()

      mymodels_iterator = serializers.deserialize(“xml”,fixed_pk_serialized_xml_model)

      mymodels_iterator中的mymodel:

      mymodel.object.id = None
      mymodel.object.pk = None
      mymodel.save()
      
    3. 它有效!

      感谢Evgeny关于clone()方法的评论。