使用棉花糖序列化应用JSON模式

时间:2019-01-17 21:27:11

标签: json marshmallow

我正在使用棉花糖对JSON字符串进行序列化和反序列化。从棉花糖API文档(https://marshmallow.readthedocs.io/en/3.0/api_reference.html)中,您似乎已经指定了字段的列表(并且,除非使用Meta,否则为其数据类型。例如:

Marital_Status=Fields.Str()
Employer=Fields.Str()
ContactInfo(data) #where ContactInfo is a class not shown here

但是,我已经有一个JSON模式,用于指定字段和数据类型。例如:

the_template_schema={

"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"type": "object",
"title": "The Root Schema",
"properties": {
 "Marital_Status": {
  "$id": "#/properties/Marital_Status",
  "type": "string",
  "title": "The Marital_status Schema",
  "default": "",
  "examples": [
    "Married"
  ],
  "pattern": "^(.*)$"
}
"Employer": {
  "$id": "#/properties/Employer",
  "type": "string",
  "title": "The Employer Schema",
  "default": "",
  "examples": [
    "Roivant"
  ],
  "pattern": "^(.*)$"
        }

    }
}

我的问题

我想根据提供的模式数据,指定棉花糖使用的字段。像这样:

fields.magicmethod(the_template_schema)
ContactInfo(data)

这可能吗?如果可以,怎么办?

2 个答案:

答案 0 :(得分:1)

在棉花糖中,应将模式指定为Python代码中的类(请参见此处的示例:https://marshmallow.readthedocs.io/en/3.0/quickstart.html#declaring-schemas)。

对于您的情况,可能看起来像

from marshmallow import Schema, fields

class ContactInfoSchema(Schema):
    Marital_Status=Fields.Str()
    Employer=Fields.Str()

您需要使用棉花糖吗?如果您的模式已经以json-schema格式存在,则可以使用json.load加载对象,并使用jsonschema模块针对该模式进行验证。

https://medium.com/python-pandemonium/json-the-python-way-91aac95d4041

https://python-jsonschema.readthedocs.io/en/latest/

答案 1 :(得分:1)

您可以编写自己的转换器,该转换器将采用JSON模式并从中创建动态棉花糖模式。

这是一个示例(它不是JSONSchema,而是更简单的东西)。

from marshmallow import Schema, fields
from functools import partial


def validator(valid_values, input):
    if input in valid_values:
        return True
    return False


def get_type(param_type):
    if param_type == "String":
        return fields.String
    if param_type == "Boolean":
        return fields.Boolean

def gen_schema(cls_name, params):
    fields = {}
    for p in params:
        field_type = get_type(p["type"])
        if p.get("valid_values"):
            fields[p["name"]] = field_type(validate=partial(validator, p["valid_values"]))
        else:
            fields[p["name"]] = field_type()
    schema = type(cls_name, (Schema,), fields)
    return schema

class ParameterSchema(Schema):
    name = fields.String(required=True)
    description = fields.String(required=False)
    required = fields.Bool(default=False)
    type = fields.String(required=True)
    valid_values = fields.List(fields.String, required=False)

p = [
  {"name": "filename",
   "description": "Should be a filename",
   "required": True,
   "type": "String",
   "valid_values": ["hello.txt", "foo.py", "bar.png"]
  },
  {"name": "SomeBool",
   "description": "Just a bool",
   "required": True,
   "type": "Boolean",
  },
  {"name": "NotRequiredBool",
   "description": "Another bool thats not required",
   "required": False,
   "type": "Boolean"
  }
]

req1 = {"filename": "foo.py", "SomeBool": False}
req2 = {"filename": "hi.txt", "SomeBool": True, "NotRequiredBool": False}

schema = ParameterSchema()
params1 = schema.load(p, many=True)

dynamic_schema = gen_schema("D1", params1.data)()

dynamic_res1 = dynamic_schema.load(req1)
dynamic_res2 = dynamic_schema.load(req2)
print(dynamic_res1)
print(dynamic_res2)

运行此打印:

UnmarshalResult(data={'filename': 'foo.py', 'SomeBool': False}, errors={})
UnmarshalResult(data={'NotRequiredBool': False, 'SomeBool': True}, errors={'filename': ['Invalid value.']})

您只需更改gen_schema即可接受有效的JSONSchema,而不是我在此处编写的简单JSONSchema。

希望有帮助。