如何将 'load_from' 和 'dump_to' 应用于棉花糖模式中的每个字段?

How to apply 'load_from' and 'dump_to' to every field in a marshmallow schema?

我一直在尝试实现一个 'abstract' 模式 class,它将自动将 CamelCase(序列化)中的值转换为 snake_case(反序列化)。

class CamelCaseSchema(marshmallow.Schema):
    @marshmallow.pre_load
    def camel_to_snake(self, data):
        return {
            utils.CaseConverter.camel_to_snake(key): value for key, value in data.items()
        }

    @marshmallow.post_dump
    def snake_to_camel(self, data):
        return {
            utils.CaseConverter.snake_to_camel(key): value for key, value in data.items()
        }

虽然使用这样的东西效果很好,但它并不能实现将 load_fromdump_to 应用于字段的所有功能。也就是说,当出现反序列化问题时,它无法提供正确的字段名称。例如,我得到: {'something_id': [u'Not a valid integer.']} 而不是 {'somethingId': [u'Not a valid integer.']}.

虽然我可以 post 处理这些发出的错误,但这似乎是一种不必要的耦合,如果我要使模式的使用完全透明,我希望避免这种耦合。

有什么想法吗?我尝试处理所涉及的元classes,但复杂性有点让人难以承受,一切看起来都异常丑陋。

您正在使用 marshmallow 2。Marshmallow 3 现已推出,我建议您使用它。我的回答将适用于棉花糖 3。

在 marshmallow 3 中,load_from / dump_to 已被单个属性替换:data_key.

实例化架构时,您需要在每个字段中更改 data_key。这将在字段实例化之后发生,但我认为这不重要。

您希望在实例化模式时尽快执行此操作以避免不一致问题。正确的时机是在 Schema._init_fields 的中间,然后检查 data_key 属性的一致性。但是复制这种方法会很遗憾。此外,由于 camel/snake 大小写转换的性质,无论如何都可以在转换之前应用一致性检查。

并且由于 _init_fields 是私有的 API,我建议在 __init__ 的末尾进行修改。

class CamelCaseSchema(Schema):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        for field_name, field in self.fields.items():
            fields.data_key = utils.CaseConverter.snake_to_camel(field_name)

我没试过,但我认为它应该有用。