pydantic Schema

1.根据模型自动创建JSON结构

from enum import Enum
from pydantic import BaseModel, Field


class FooBar(BaseModel):
    count: int
    size: float = None


class Gender(str, Enum):
    male = 'male'
    female = 'female'
    other = 'other'
    not_given = 'not_given'


class MainModel(BaseModel):
    """
    This is the description of the main model
    """

    foo_bar: FooBar = Field(...)
    gender: Gender = Field(None, alias='Gender')
    snap: int = Field(
        42,
        title='The Snap',
        description='this is the value of snap',
        gt=30,
        lt=50,
    )

    class Config:
        title = 'Main'


# this is equivalent to json.dumps(MainModel.schema(), indent=2):
print(MainModel.schema_json(indent=2))  # indent=2 表示缩进空格数

2.获取指定类型的JSON架构

  • schema_of
  • schema_json_of
from typing import Literal, Union

from typing_extensions import Annotated

from pydantic import BaseModel, Field, schema_json_of


class Cat(BaseModel):
    pet_type: Literal['cat']
    cat_name: str


class Dog(BaseModel):
    pet_type: Literal['dog']
    dog_name: str


Pet = Annotated[Union[Cat, Dog], Field(discriminator='pet_type')]

print(schema_json_of(Pet, title='The Pet Schema', indent=2))
"""
{
  "title": "The Pet Schema",
  "discriminator": {
    "propertyName": "pet_type",
    "mapping": {
      "cat": "#/definitions/Cat",
      "dog": "#/definitions/Dog"
    }
  },
  "anyOf": [
    {
      "$ref": "#/definitions/Cat"
    },
    {
      "$ref": "#/definitions/Dog"
    }
  ],
  "definitions": {
    "Cat": {
      "title": "Cat",
      "type": "object",
      "properties": {
        "pet_type": {
          "title": "Pet Type",
          "enum": [
            "cat"
          ],
          "type": "string"
        },
        "cat_name": {
          "title": "Cat Name",
          "type": "string"
        }
      },
      "required": [
        "pet_type",
        "cat_name"
      ]
    },
    "Dog": {
      "title": "Dog",
      "type": "object",
      "properties": {
        "pet_type": {
          "title": "Pet Type",
          "enum": [
            "dog"
          ],
          "type": "string"
        },
        "dog_name": {
          "title": "Dog Name",
          "type": "string"
        }
      },
      "required": [
        "pet_type",
        "dog_name"
      ]
    }
  }
}
"""
  • BaseModel.schema
import json
from pydantic import BaseModel
from pydantic.schema import schema


class Foo(BaseModel):
    a: str = None


class Model(BaseModel):
    b: Foo


class Bar(BaseModel):
    c: int


top_level_schema = schema([Model, Bar], title='My Schema')
print(json.dumps(top_level_schema, indent=2))
  • BaseModel.schema_json

3.修改字段中的Schema展示

from typing import Optional

from pydantic import BaseModel, Field
from pydantic.fields import ModelField


class RestrictedAlphabetStr(str):

    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, value, field: ModelField):
        """
        增加校验,严格限制value值必须是ABC
        如果不对字段进行限制,可以不用实现该方法和__get_validators__方法
        """
        alphabet = field.field_info.extra['alphabet']
        if any(c not in alphabet for c in value):
            raise ValueError(f'{value!r} is not restricted to {alphabet!r}')
        return cls(value)

    @classmethod
    def __modify_schema__(cls, field_schema, field: Optional[ModelField]):
        if field:
            alphabet = field.field_info.extra['alphabet']
            field_schema['examples'] = [c * 3 for c in alphabet]


class MyModel(BaseModel):
    value: RestrictedAlphabetStr = Field(alphabet='ABC')


# Schema结构中增加examples示例:__modify_schema__
print(MyModel.schema_json(indent=2))
print(MyModel(value="ABC"))

4.通过配置扩展Schema

from pydantic import BaseModel


class Person(BaseModel):
    name: str
    age: int

    class Config:
        schema_extra = {
            'examples': [
                {
                    'name': 'John Doe',
                    'age': 25,
                }
            ]
        }


print(Person.schema_json(indent=2))


"""
{
  "title": "Person",
  "type": "object",
  "properties": {
    "name": {
      "title": "Name",
      "type": "string"
    },
    "age": {
      "title": "Age",
      "type": "integer"
    }
  },
  "required": [
    "name",
    "age"
  ],
  "examples": [
    {
      "name": "John Doe",
      "age": 25
    }
  ]
}
"""

5.自定义schema

  • 使用model层字段中的描述信息来填充schema中的描述
from typing import Dict, Any, Type

from sqlalchemy import Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel, Field

Base = declarative_base()


class PersonOrm(Base):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True, nullable=False, comment="primary_key")
    name = Column(String(63))


class Person(BaseModel):
    id: int = Field(...)
    name: str = Field(..., title='The Snap', description='this is the value of snap')

    class Config:
        orm_mode = True
        orm_model = PersonOrm

        @staticmethod
        def schema_extra(schema: Dict[str, Any], model: Type['Person']) -> None:
            model_obj = model.Config().orm_model()
            for key, value in schema.get('properties', {}).items():
                if value.get("description"):
                    continue
                if hasattr(model_obj, key):
                    description = model_obj.metadata.sorted_tables[0].columns._index[key].comment
                    value["description"] = description


person_orm = PersonOrm(id=123, name='Testing')
person_model = Person.from_orm(person_orm)
print(person_model.schema_json(indent=2))

"""
C:\Users\fatpuffer\AppData\Local\pypoetry\Cache\virtualenvs\baseapi-FOv_RZhh-py3.7\Scripts\python.exe F:/projects/BaseApi/__init__.py
{
  "title": "Person",
  "type": "object",
  "properties": {
    "id": {
      "title": "Id",
      "type": "integer",
      "description": "primary_key"
    },
    "name": {
      "title": "The Snap",
      "description": "this is the value of snap",
      "type": "string"
    }
  },
  "required": [
    "id",
    "name"
  ]
}
"""

5.Field字段属性

  • default:字段默认值,...或空,代表必填;None代表可选
  • default_factory:可以设置动态默认值,不能和default同时设置
  • alias:字段设置别名,在dict获取时,可通过设置by_alias=True参数得到别名对象
  • title:生成的schema文档title字段值
  • description:schema中对字段的描述
  • exclude:表示字段是否被排除在外,不进行展示
  • include:表示是否仅展示该字段
  • const:布尔值,必须和default保持一致,schema中可以看到该字段的值就是default默认值
  • gt:对于数值,大于该参数设置的值
  • ge:对于数值,大于或等于该参数设置的值
  • lt:对于数值,小于该参数设置的值
  • le:对于数值,小于或等于该参数设置的值
  • multiple_of:对于整数,校验倍数,比如multiple_of=2,则该参数接收的值只能是2的倍数
  • max_digits:对于Decimal类型,校验位数,不包括小数点,仅计算整数位+小数位的最大长度(小数位末尾的0不算在内,整数部分开头的0不算在内),不超过该参数设置
  • decimal_places:对于Decimal类型,校验小位数(小数位末尾的0不算在内),不超过该参数设置
  • min_items:对于列表(typing下的List)值,长度不能小于该参数设置的值
  • max_items:对于列表值,长度不能大于该参数设置的值
  • unique_items:对于列表值,不能有重复的元素
  • min_length:对于字符串值,最小长度不能小于该参数设置的值
  • max_length:对于字符串值,最大长度不能大于该参数设置的值
  • allow_mutation:布尔值,该字段参数是否可以被修改
  • regex:对于字符串值,可以直接传递正则进行校验
posted @ 2022-06-16 16:20  fatpuffer  阅读(355)  评论(0编辑  收藏  举报