跳转到主要内容

用于简化将结构转换为或从JSON读取的处理。

项目描述

Jazzband https://badge.fury.io/py/jsonmodels.svg Tests PyPI Coverage

jsonmodels 是一个库,使您更容易处理转换为或从JSON读取的结构。

特性

  • 完全在Python 3.8+上测试。

  • 支持PyPy 3.9和3.10(有关更多详细信息,请参阅文档中的实现说明)。

  • 创建类似Django的模型

    from jsonmodels import models, fields, errors, validators
    
    
    class Cat(models.Base):
    
        name = fields.StringField(required=True)
        breed = fields.StringField()
        love_humans = fields.IntField(nullable=True)
    
    
    class Dog(models.Base):
    
        name = fields.StringField(required=True)
        age = fields.IntField()
    
    
    class Car(models.Base):
    
        registration_number = fields.StringField(required=True)
        engine_capacity = fields.FloatField()
        color = fields.StringField()
    
    
    class Person(models.Base):
    
        name = fields.StringField(required=True)
        surname = fields.StringField(required=True)
        nickname = fields.StringField(nullable=True)
        car = fields.EmbeddedField(Car)
        pets = fields.ListField([Cat, Dog], nullable=True)
  • 通过属性访问值

    >>> cat = Cat()
    >>> cat.populate(name='Garfield')
    >>> cat.name
    'Garfield'
    >>> cat.breed = 'mongrel'
    >>> cat.breed
    'mongrel'
  • 验证模型

    >>> person = Person(name='Chuck', surname='Norris')
    >>> person.validate()
    None
    
    >>> dog = Dog()
    >>> dog.validate()
    *** ValidationError: Field "name" is required!
  • 将模型转换为python结构和JSON

    >>> cat = Cat(name='Garfield')
    >>> dog = Dog(name='Dogmeat', age=9)
    >>> car = Car(registration_number='ASDF 777', color='red')
    >>> person = Person(name='Johny', surname='Bravo', pets=[cat, dog])
    >>> person.car = car
    >>> person.to_struct()
    {
        'car': {
            'color': 'red',
            'registration_number': 'ASDF 777'
        },
        'surname': 'Bravo',
        'name': 'Johny',
        'nickname': None,
        'pets': [
            {'name': 'Garfield'},
            {'age': 9, 'name': 'Dogmeat'}
        ]
    }
    
    >>> import json
    >>> person_json = json.dumps(person.to_struct())
  • 您不喜欢编写JSON Schema?让 jsonmodels 为您完成

    >>> person = Person()
    >>> person.to_json_schema()
    {
        'additionalProperties': False,
        'required': ['surname', 'name'],
        'type': 'object',
        'properties': {
            'car': {
                'additionalProperties': False,
                'required': ['registration_number'],
                'type': 'object',
                'properties': {
                    'color': {'type': 'string'},
                    'engine_capacity': {'type': ''},
                    'registration_number': {'type': 'string'}
                }
            },
            'surname': {'type': 'string'},
            'name': {'type': 'string'},
            'nickname': {'type': ['string', 'null']}
            'pets': {
                'items': {
                    'oneOf': [
                        {
                            'additionalProperties': False,
                            'required': ['name'],
                            'type': 'object',
                            'properties': {
                                'breed': {'type': 'string'},
                                'name': {'type': 'string'}
                            }
                        },
                        {
                            'additionalProperties': False,
                            'required': ['name'],
                            'type': 'object',
                            'properties': {
                                'age': {'type': 'number'},
                                'name': {'type': 'string'}
                            }
                        },
                        {
                            'type': 'null'
                        }
                    ]
                },
                'type': 'array'
            }
        }
    }
  • 验证模型并使用影响生成的架构的验证器

    >>> class Person(models.Base):
    ...
    ...     name = fields.StringField(
    ...         required=True,
    ...         validators=[
    ...             validators.Regex('^[A-Za-z]+$'),
    ...             validators.Length(3, 25),
    ...         ],
    ...     )
    ...     age = fields.IntField(
    ...         nullable=True,
    ...         validators=[
    ...             validators.Min(18),
    ...             validators.Max(101),
    ...         ]
    ...     )
    ...     nickname = fields.StringField(
    ...         required=True,
    ...         nullable=True
    ...     )
    ...
    
    >>> person = Person()
    >>> person.age = 11
    >>> person.validate()
    *** ValidationError: '11' is lower than minimum ('18').
    >>> person.age = None
    >>> person.validate()
    None
    
    >>> person.age = 19
    >>> person.name = 'Scott_'
    >>> person.validate()
    *** ValidationError: Value "Scott_" did not match pattern "^[A-Za-z]+$".
    
    >>> person.name = 'Scott'
    >>> person.validate()
    None
    
    >>> person.nickname = None
    >>> person.validate()
    *** ValidationError: Field is required!
    
    >>> person.to_json_schema()
    {
        "additionalProperties": false,
        "properties": {
            "age": {
                "maximum": 101,
                "minimum": 18,
                "type": ["number", "null"]
            },
            "name": {
                "maxLength": 25,
                "minLength": 3,
                "pattern": "/^[A-Za-z]+$/",
                "type": "string"
            },
            "nickname": {,
                "type": ["string", "null"]
            }
        },
        "required": [
            "nickname",
            "name"
        ],
        "type": "object"
    }

    您还可以在需要时验证标量

    >>> class Person(models.Base):
    ...
    ...     name = fields.StringField(
    ...         required=True,
    ...         validators=[
    ...             validators.Regex('^[A-Za-z]+$'),
    ...             validators.Length(3, 25),
    ...         ],
    ...     )
    ...     age = fields.IntField(
    ...         nullable=True,
    ...         validators=[
    ...             validators.Min(18),
    ...             validators.Max(101),
    ...         ]
    ...     )
    ...     nickname = fields.StringField(
    ...         required=True,
    ...         nullable=True
    ...     )
    ...
    
    >>> def only_odd_numbers(item):
    ... if item % 2 != 1:
    ...    raise validators.ValidationError("Only odd numbers are accepted")
    ...
    >>> class Person(models.Base):
    ... lucky_numbers = fields.ListField(int, item_validators=[only_odd_numbers])
    ... item_validator_str = fields.ListField(
    ...        str,
    ...        item_validators=[validators.Length(10, 20), validators.Regex(r"\w+")],
    ...        validators=[validators.Length(1, 2)],
    ...    )
    ...
    >>> Person.to_json_schema()
    {
        "type": "object",
        "additionalProperties": false,
        "properties": {
            "item_validator_str": {
                "type": "array",
                "items": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 20,
                    "pattern": "/\\w+/"
                },
                "minItems": 1,
                "maxItems": 2
            },
            "lucky_numbers": {
                "type": "array",
                "items": {
                    "type": "number"
                }
            }
        }
    }

(注意,only_odd_numbers 不会修改架构,因为只有基于类的验证器才能做到这一点,尽管它在Python中仍将按预期工作。如果要在架构方面100%正确,请使用可以表示为json schema的基于类的验证器。)

  • 懒加载,最适合循环引用

    >>> class Primary(models.Base):
    ...
    ...     name = fields.StringField()
    ...     secondary = fields.EmbeddedField('Secondary')
    
    >>> class Secondary(models.Base):
    ...
    ...    data = fields.IntField()
    ...    first = fields.EmbeddedField('Primary')

    您可以使用 模型,完整路径 path.to.Model 或相对导入 .Model…Model

  • 使用定义来生成循环引用的方案

    >>> class File(models.Base):
    ...
    ...     name = fields.StringField()
    ...     size = fields.FloatField()
    
    >>> class Directory(models.Base):
    ...
    ...     name = fields.StringField()
    ...     children = fields.ListField(['Directory', File])
    
    >>> class Filesystem(models.Base):
    ...
    ...     name = fields.StringField()
    ...     children = fields.ListField([Directory, File])
    
    >>> Filesystem.to_json_schema()
    {
        "type": "object",
        "properties": {
            "name": {"type": "string"}
            "children": {
                "items": {
                    "oneOf": [
                        "#/definitions/directory",
                        "#/definitions/file"
                    ]
                },
                "type": "array"
            }
        },
        "additionalProperties": false,
        "definitions": {
            "directory": {
                "additionalProperties": false,
                "properties": {
                    "children": {
                        "items": {
                            "oneOf": [
                                "#/definitions/directory",
                                "#/definitions/file"
                            ]
                        },
                        "type": "array"
                    },
                    "name": {"type": "string"}
                },
                "type": "object"
            },
            "file": {
                "additionalProperties": false,
                "properties": {
                    "name": {"type": "string"},
                    "size": {"type": "number"}
                },
                "type": "object"
            }
        }
    }
  • 处理无模式数据

(请注意,使用无模式字段可能导致您的模型失去控制 - 尤其如果您是数据模式的责任人。另一方面,通常情况下,传入的数据没有定义模式,无模式字段是最佳选择。)

>>> class Event(models.Base):
...
...     name = fields.StringField()
...     size = fields.FloatField()
...     extra = fields.DictField()

>>> Event.to_json_schema()
{
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "extra": {
            "type": "object"
        },
        "name": {
            "type": "string"
        },
        "size": {
            "type": "float"
        }
    }
}

DictField 允许传递任何值的字典(“type”: “object”),但请注意,它不会对值进行任何验证,除了字典类型。

  • 比较 JSON 方案

    >>> from jsonmodels.utils import compare_schemas
    >>> schema1 = {'type': 'object'}
    >>> schema2 = {'type': 'array'}
    >>> compare_schemas(schema1, schema1)
    True
    >>> compare_schemas(schema1, schema2)
    False

更多

有关更多示例和更详细的描述,请参阅完整文档:http://jsonmodels.rtfd.org

历史

2.7.0 (2023-12-17)

  • 添加了 Python 3.12,PyPy 3.9 和 3.10 支持。

  • 移除了 Python 3.7 和 PyPy 3.8 支持。

2.6.0 (2022-10-14)

  • 移除了 Python 3.6 支持。

  • 添加了对 Python 3.11 的支持。

2.5.1 (2022-06-16)

  • 指定 PyPy 版本为 PyPy 3.8。

  • 添加了对 Python 3.10 的支持。

2.5.0 (2021-07-26)

  • 改进了字段验证错误的错误信息。

  • 允许验证非模型列表项。

  • 添加了 DictField。

2.4.1 (2021-02-19)

  • 添加了 Python 3.8 和 3.9 支持。

  • 移除了 Python 2.7、3.3 和 3.5 支持。

2.4 (2018-12-01)

  • 修复了长度验证器。

  • 添加了对 Python 3.7 的支持。

2.3 (2018-02-04)

  • 为字段添加了名称映射。

  • 为 IntField 添加了值解析。

  • 修复了 ECMA 正则表达式标志识别的漏洞。

2.2 (2017-08-21)

  • 修复了时间字段,当值不是必需时。

  • 放弃了 Python 2.6 支持。

  • 添加了对 Python 3.6 的支持。

  • 为字段添加了可为空的参数。

  • 改进了模型表示。

2.1.5 (2017-02-01)

  • 修复了 DateTimefield 在值为 None 时的错误。

  • 修复了没有必需值的模型比较。

2.1.4 (2017-01-24)

  • 允许根据类型和字段(而不是它们的引用)比较模型。

2.1.3 (2017-01-16)

  • 修复了生成的方案。

  • 改进了 JSON 序列化。

2.1.2 (2016-01-06)

  • 修复了内存泄漏。

2.1.1 (2015-11-15)

  • 添加了对 Python 2.6、3.2 和 3.5 的支持。

2.1 (2015-11-02)

  • 添加了类型的懒加载。

  • 添加了循环模型的方案生成。

  • 改进了验证错误的可读性。

  • 修复了列表字段的生成结构。

2.0.1 (2014-11-15)

  • 修复了原始类型的方案生成。

2.0 (2014-11-14)

  • 字段现在是描述符。

  • 空的需求字段仅在显式验证期间进行验证。

向后兼容性中断

  • 字段中的 _types 重命名为 types。

  • ListField 中的 _items_types 重命名为 items_types。

  • 移除了数据转换器。

  • 将模块 error 重命名为 errors

  • 移除了显式验证 - 验证发生在分配时间。

  • get_value_replacement 重命名为 get_default_value

  • 将模块 utils 重命名为 utilities

1.4 (2014-07-22)

  • 允许验证器修改生成的方案。

  • 添加了最大值验证器。

  • 添加了在 Python 和 ECMA 格式之间转换正则表达式的实用工具。

  • 添加了正则表达式验证器。

  • 添加了最小值验证器。

  • 默认情况下,字段“validators”属性是一个空列表。

1.3.1 (2014-07-13)

  • 修复了 BoolField 的方案生成。

1.3 (2014-07-13)

  • 添加了新的字段(BoolField、TimeField、DateField 和 DateTimeField)。

  • ListField 总是不必需的。

  • 现在可以从类本身(而不是实例)生成方案。

1.2 (2014-06-18)

  • 修复了当值不是字典时的值填充。

  • 添加了自定义验证器。

  • 添加了方案比较工具。

1.1.1 (2014-06-07)

  • 添加了将已初始化的数据填充到嵌入式字段的可能。

  • 添加了 compare_schemas 实用工具。

1.1 (2014-05-19)

  • 添加了文档。

  • 添加了 JSON 方案生成。

  • 添加了用于 PEP8 和复杂性的测试。

  • 迁移到 Python 3.4。

  • 添加了 PEP257 兼容性。

  • 为字段添加了帮助文本。

1.0.5 (2014-04-14)

  • 添加了数据转换器。

1.0.4 (2014-04-13)

  • 列表字段现在支持简单类型。

1.0.3 (2014-04-10)

  • 修复了与Python 3的兼容性。

  • 修复了strrepr方法。

1.0.2 (2014-04-03)

  • 添加了深度数据初始化。

1.0.1 (2014-04-03)

  • 添加了populate方法。

1.0 (2014-04-02)

  • PyPI上的第一个稳定版本。

0.1.0 (2014-03-17)

  • PyPI上的第一个版本。

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定选择哪一个,请了解有关安装包的更多信息。

源代码分发

jsonmodels-2.7.0.tar.gz (33.2 kB 查看哈希值)

上传时间 源代码

构建分发

jsonmodels-2.7.0-py3-none-any.whl (18.2 kB 查看哈希值)

上传时间 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面