【问题标题】:Django Model deserialization with empty PK带有空 PK 的 Django 模型反序列化
【发布时间】:2009-07-16 10:44:39
【问题描述】:

我已经序列化了我的 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 模型并将 save() 保存到数据库中,但使用不同的 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 可以为空,但在 XML 中它会抱怨。如何将 XML 的 pk 设置为 null?

谢谢

【问题讨论】:

标签: django serialization


【解决方案1】:

看起来像 Django 中的错误。无法为 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 设置“pk”
  4. 反序列化为模型
  5. 保存()

这有点棘手,因为在步骤 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()
    

而且它有效!

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

【讨论】:

  • 只是一个想法 - 如果解析器正在验证,那么它不会让您设置无效值,例如 Null。还有 - 你的主键是自动递增的吗?如果是,那么您可能不想手动设置它们,我会创建一个类似 clone() 的方法或寻找类似的方法...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 1970-01-01
  • 2019-04-08
相关资源
最近更新 更多