FastAPI 基础入门(五)

发布于:2025-06-30 ⋅ 阅读:(17) ⋅ 点赞:(0)

FastAPI 基础入门(五)

本章源码

Pydantic数据模型管理

5.1 Pydantic介绍

Pydantic是一个使用Python类型注解进行数据验证和管理的模块。它可以在代码运行时强制进行类型验证,当数据类型不符或数据无效时抛出友好的错误提示。这个功能可让开发者及时了解错误信息。FastAPI框架整合了Pydantic,以求为开发者提供更多便利。

❑ 支持使用Python的类型提示来定义数据模型,这使得代码更加易于阅读和维护。

❑ 提供了一些内置的验证器,可以对输入数据进行验证,确保输入的数据类型、格式、范围等符合预期。

❑ 自动解析并验证请求中的视图函数参数、查询参数以及Body参数等。

❑ 支持复杂数据结构定义以及验证。

❑ 相比valideer库、marshmallow库、trafaret库以及cerberus库等,在速度上更具优势。

❑ 支持字段进行自定义验证。

❑ 基于BaseSettings类,读取系统设置的环境变量值,还可以对其进行数据验证。

❑ 基于BaseModel基类,再结合数据库ORM可以进行序列化和反序列化操作,在操作过程中还可以对相关字段进行过滤。

❑ Pydantic可以自动生成API文档,包括请求和响应的数据类型。

5.2 Pydantic使用

❑ Web框架:Pydantic可以帮助开发人员定义请求和响应数据模型,以及执行数据验证和转换。Pydantic还可以自动生成API文档,包括请求和响应的数据模型。

❑ 数据库访问:Pydantic可以帮助开发人员定义ORM模型,并进行数据验证和转换。

❑ 数据分析:Pydantic可以帮助开发人员处理数据集,进行数据验证和转换。

pip install pydantic

需要基于Pydantic的BaseSettings类来读取环境变量,那么还需要安装dotenv库。

pip install pydantic[dotenv]

5.2.1 模型常见数据类型

每一个模型对象都继承于BaseModel类,且模型类中的每一个属性都有自己的数据类型。
常见的数据类型有bool、int、str、bytes、list、tuple、dict、set等。Pydantic还支持datetime、FilePath、DirectoryPath、EmailStr、NameEmail(邮箱格式类型)、Color、AnyUrl(任意网址)、HTTPUrl、Json、IPvAnyAddress、IPvAnyNetwork、SecretStr和SecretBytes(敏感数据类型)等特殊数据类型.

from typing import Union, Optional, List

from pydantic import BaseModel, \
    DirectoryPath, \
    IPvAnyAddress, \
    FilePath, \
    EmailStr, \
    NameEmail, SecretStr, SecretBytes, ValidationError, HttpUrl
from datetime import date


class Person(BaseModel):
    # 基础类型
    name: str  # 字符串类型
    age: int  # 整形类型
    enable: bool  # 布尔类型
    hobby: list  # 列表类型
    adress: dict  # 字典类型
    birthday: date  # datetime中的时间类型

    # 其他复杂的对象类型
    filePath: FilePath  # 文件路径类型
    directoryPath: DirectoryPath  # 文件目录类型
    ip: IPvAnyAddress  # IP地址类型
    emailStr: EmailStr  # 电子邮件地址类型
    nameEmail: NameEmail  # 有效格式的电子邮件地址类型
    secretStr: SecretStr  # 敏感信息数据类型,最终会被格式化为'**'进行代替覆盖
    secretBytes: SecretBytes  # 同步是敏感数据类型
    website: HttpUrl

5.2.2 模型参数必选和可选

如果对模型的属性没有进行任何赋值操作,在Pydantic内部会默认把这些值对应的字段设置为必传的字段,但是在实际应用中,有可能不需要对所有字段进行这种校验,比如对于有默认值的字段或者处于可选状态的字段。可以通过下面的方式来进行参数字段的声明和赋值:

class Person(BaseModel):
    name:str
    age:Optional[int]
    age2:Optional[int] = None
    gender:str = '男'
    idnum:Union[int,str]
    dict_str_float_parse:Dict[str,float] = None
    

对上面的模型类涉及的参数声明说明如下:

❑name参数的值是字符串类型,这是一个必填参数,也就是说实例化必须传入name的值。

❑age参数由于使用Optional来声明,所以它是一个选填参数。如果它存在值,则必须是一个int类型的值。Optional在这里主要表示当前参数是可选类型的参数。

❑age2参数和age参数一样,只是age2参数显式设置了一个默认值None。

❑gender参数也是一个选填参数,如果没有指定传值,则默认的值是“男”。

❑idnum参数使用Union声明后,表示该参数是一个必填项,且参数类型有int类型或者str类型,不过它内部会强制仅限于Union[int, str]中所描述的数据类型,Union主要为IDE做一个比较友好的提示,方便开发者知道这个参数建议的值是什么类型

❑dict_str_float_parse参数则使用dict字典来声明,且对键值对类型也进行了声明。

5.2.3 模型多层嵌套

在实际应用场景中有可能需要模型嵌套或更深层次的嵌套,Pydantic对这些嵌套模型都是可以支持的,代码如下:

class Card(BaseModel):
    nums:str

class Person(BaseModel):
    name:str
    age:str
    cards:Optional[List[Card]]

在Person模型中内嵌了一个Card列表类型对象,且声明它是一个可选参数。

5.2.4 模型对象实例化

下面介绍模型实例化,代码如下:

class Person(BaseModel):
    name:str
    nums:str
    age:Optional[int]

if __name__ == "__main__":
    user = Person(name = "xiaozhang",nums = "21",age = 15)
    print(user.name,user.age)

实例化Person对象非常简单,只需要传入具体参数即可完成对象创建。但是在一些复查业务场景中,需要基于一些已有的对象来完成模型对象的实例化。BaseModel提供了非常多的方法让用户可以结合不同的业务场景来实现模型对象的创建,它提供的主要静态方法如下:

BaseModel.parse_obj():传入字典,完成对象初始化。该方式和实例化传参方式基本一样,知识要求传参类型必须是字典。

BaseModel.parse_raw():传入字符串或字节对象,自动解析为json对象,然后完成对象初始化。

BaseModel.parse_file():基于文件对象方式解析并完成对象初始化

BaseModel.from_orm():从数据库orm模型对象中实例初始化对象。

5.2.5 模型对象的转换

当模型对象实例化完成后,在某些业务场景中经常需要对模型对象进行一些数据格式转换,比如转换为dict或JSON格式的数据,转换后可以方便用户将其作为数据库的模型进行数据处理.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from typing import Union, Optional, List
from pydantic import BaseModel, ValidationError

class Person(BaseModel):
    name: str
    password: str
    age: int
    enable: bool = True

if __name__ == '__main__':
    try:
        user = Person(name='xiaozhong', password='123456', age=15)
    except ValidationError as e:
        print(e.errors())
        print(e.json())
    else:
        print(user.model_dump(exclude_unset=True))
        print(user.model_dump_json(exclude={'password'}))
        
        # 正确用法:使用 update 参数来更新字段值
        # 这会创建一个新的 Person 对象,其中 password 已被更新,其他字段保持不变
        new_user = user.model_copy(update={'password': "a_new_password"})
        
        print("new_user", new_user)
        print("new_user id:", id(new_user))
        print("original user id:", id(user)) # 验证 new_user 是一个新对象

在这里插入图片描述

5.2.6 模型对象复制

除了dict()和json()方法。在一些场景需要进行一些模型实例化对象的复制,此时需要用到copy()

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from typing import Union, Optional, List
from pydantic import BaseModel, ValidationError


class Person(BaseModel):
    # 基础类型
    name: str  # 字符串类型
    password: str  # 字符串类型
    age: int  # 整形类型
    enable: bool = True  # 布尔类型

if __name__ == '__main__':
    try:
        user = Person(name='xiaozhong', password='123456', age=15)
    except ValidationError as e:
        print(e.errors())
        print(e.json())
    else:
        # Print the dictionary representation of the user, excluding unset fields
        print(user.model_dump(exclude_unset=True))
        print(user.model_dump_json(exclude={'password'}))

        # Copy the user, including only the 'password' field
        new_user = user.model_copy(update={'password': '123'})  # Correct way to use update
        print("new_userID", new_user, id(new_user))

在这里插入图片描述

5.2.7 异常信息的捕获

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
from typing import Dict, Optional

from pydantic import BaseModel, field_validator, ValidationError, PydanticValueError

class AddressError(PydanticValueError):
    code = '错误类型'
    msg_template = '当前地址长度不对,它应该需要{errmeg},当前传入的值为:{value}'

class Person(BaseModel):
    username: str
    address: str

    @field_validator("address",pre=False)
    def adress_rule(cls, address):
        # 如果地址长度小于6,那么则返回
        if len(address) < 6:
            raise AddressError(errmeg='小于6',value=address)
        elif len(address) > 12:
            raise AddressError(errmeg='大于12',value=address)
        return address

if __name__ == '__main__':
    # try:
    #     user = Person(username='xiaozhong', address='12345')
    # except ValidationError as e:
    #     print(e.errors())
    # else:
    #     print(user.username, user.address)


    class Person(BaseModel):
        name: str
        nums: str
        age: Optional[int]


    if __name__ == '__main__':
        try:
            user = Person(name='xiaozhong')
        except ValidationError as e:
            # print(e.errors())
            # print(e.json())
            print(str(e))
        else:
            print(user.name, user.age)
Traceback (most recent call last):
  File "/Users/fishyuu/2025_learn/fastapi_tutorial/chapter05/pydantic_validator/person_main.py", line 13, in <module>
    user = Person(name='xiaozhong')
  File "/Users/fishyuu/Library/Python/3.9/lib/python/site-packages/pydantic/main.py", line 253, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
pydantic_core._pydantic_core.ValidationError: 2 validation errors for Person
nums
  Field required [type=missing, input_value={'name': 'xiaozhong'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing
age
  Field required [type=missing, input_value={'name': 'xiaozhong'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing

错误提示,nums是必选参数,由于实例化没有传参赋值,触发ValidationError异常。对于这种异常信息,需要在程序中知道具体的错误明细,可以通过捕获抛出的ValidationError异常对象进行解析,代码如下:

from typing import Optional

from pydantic import BaseModel,ValidationError


class Person(BaseModel):
    name:str
    nums:str
    age:Optional[str]


if __name__ == "__main__":
    try:
        user = Person(name='xiaozhong')
        print(user.name)
    except ValidationError as e:
        print("##### e.errors()输出结果 #####")
        print(e.errors())
        print("##### e.json()输出结果 #####")
        print(e.json())
        print("##### str(e)输出结果 #####")
        print(str(e))
    else:
        print(user.name,user.age)

输出结果:

❑e.errors():通过列表的形式返回所有错误信息内容

❑e.json():通过将e.errors()的列表错误显示进行json格式化并返回

##### e.errors()输出结果 #####
[{'type': 'missing', 'loc': ('nums',), 'msg': 'Field required', 'input': {'name': 'xiaozhong'}, 'url': 'https://errors.pydantic.dev/2.11/v/missing'}, {'type': 'missing', 'loc': ('age',), 'msg': 'Field required', 'input': {'name': 'xiaozhong'}, 'url': 'https://errors.pydantic.dev/2.11/v/missing'}]
##### e.json()输出结果 #####
[{"type":"missing","loc":["nums"],"msg":"Field required","input":{"name":"xiaozhong"},"url":"https://errors.pydantic.dev/2.11/v/missing"},{"type":"missing","loc":["age"],"msg":"Field required","input":{"name":"xiaozhong"},"url":"https://errors.pydantic.dev/2.11/v/missing"}]
##### str(e)输出结果 #####
2 validation errors for Person
nums
  Field required [type=missing, input_value={'name': 'xiaozhong'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing
age
  Field required [type=missing, input_value={'name': 'xiaozhong'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing

通过输出结果可以看出,一个ValidationError中的错误项对象就是一个字典,字典所包含的内容是:

❑loc 表示出现校验错误的字段名称。如nums

❑msg 表示出现校验错误的原因。如错误信息’Field required’,说明nums字段参数是必填参数

❑type 表示错误类型。

5.2.8 用Field()函数扩展更多复杂验证

在前面小节介绍的模型中,字段参数仅用于数据类型的校验,无法为字段参数扩展更多的校验规则。pydantic提供了一个Field()函数,可以增加更多其他辅助验证约束规则。代码如下:

def Field(
    default: ellipsis,  # noqa: F821  # TODO: use `_typing_extra.EllipsisType` when we drop Py3.9
    *,
    alias: str | None = _Unset,
    alias_priority: int | None = _Unset,
    validation_alias: str | AliasPath | AliasChoices | None = _Unset,
    serialization_alias: str | None = _Unset,
    title: str | None = _Unset,
    field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset,
    description: str | None = _Unset,
    examples: list[Any] | None = _Unset,
    exclude: bool | None = _Unset,
    discriminator: str | types.Discriminator | None = _Unset,
    deprecated: Deprecated | str | bool | None = _Unset,
    json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset,
    frozen: bool | None = _Unset,
    validate_default: bool | None = _Unset,
    repr: bool = _Unset,
    init: bool | None = _Unset,
    init_var: bool | None = _Unset,
    kw_only: bool | None = _Unset,
    pattern: str | typing.Pattern[str] | None = _Unset,
    strict: bool | None = _Unset,
    coerce_numbers_to_str: bool | None = _Unset,
    gt: annotated_types.SupportsGt | None = _Unset,
    ge: annotated_types.SupportsGe | None = _Unset,
    lt: annotated_types.SupportsLt | None = _Unset,
    le: annotated_types.SupportsLe | None = _Unset,
    multiple_of: float | None = _Unset,
    allow_inf_nan: bool | None = _Unset,
    max_digits: int | None = _Unset,
    decimal_places: int | None = _Unset,
    min_length: int | None = _Unset,
    max_length: int | None = _Unset,
    union_mode: Literal['smart', 'left_to_right'] = _Unset,
    fail_fast: bool | None = _Unset,
    **extra: Unpack[_EmptyKwargs],
) -> Any: ...

对上述代码所涉函数中的参数说明如下:

❑default表示定义字段参数默认值。

❑default_factory表示定义一个创建默认值的工厂方法,通过这个方法可以动态进行默认值的设置。按官网说明,禁止同时设置default和default_factory。

❑alias表示定义字段参数的别名。

❑title表示定义字段参数的标题,如果没有,则默认是字段属性的值。

❑description表示定义字段参数描述。

❑exclude表示模型转换为JSON或dict时,转换结果中要排除此字段,不输出。

❑include表示模型进行转换为JSON或dict的时候,转换结果中要包含此字段信息的输出。

❑gt是一种校验规则,表示定义该字段参数的值需要大于某个float类型的值。

❑ge是一种校验规则,表示定义该字段参数的值需要大于或等于某个float类型的值。

❑lt是一种校验规则,表示定义该字段参数的值需要小于某个float类型的值。

❑le是一种校验规则,表示定义该字段参数的值需要小于或等于某个float类型的值。

❑multiple_of是一种校验规则,表示定义该字段参数的值强制设置为值的倍数,比如multiple_of=5,则该参数值必须是5的倍数。

❑max_digits是一种校验规则,表示定义该字段参数的值位数(不考虑小数点的位数)不能大于设定的值,如参数值为569.23,而max_digits限制位数为2,则此时该值就会通过异常提示不能超过两位数。

❑decimal_places是一种校验规则,表示该字段参数值中如果包含小数点,那么该值中允许的最大位数不能超过设定的值。如果参数值为3.952,但是decimal_places限制小数点位数为2,那么该值就会受限;如果参数值为3.95,则可以通过。

❑min_items是一种校验规则,表示该字段参数值如果是一个列表类型,那么它包含的列表内容至少需要设定的值,如name: List[str]=Field(…,min_items=2),而name=[‘xiao’],那么只有一项内容时不符合要求。

❑max_items是一种校验规则,和min_items相反,表示该字段参数值如果是一个列表类型,那么它包含的列表内容最多不能超过设定的值,如name: List[str]=Field(…,unique_items=True),那么此时name=[‘iii’,‘iii’]的赋值会引发重复机制验证而抛出异常。

❑min_length是一种校验规则,表示该字段参数值如果是一个字符串类型,则它的最小长度不能小于设定值。

❑max_length是一种校验规则,表示该字段参数值如果是一个字符串类型,则它的最大长度不能大于设定值。

❑allow_mutation表示该字段参数值是否允许修改,默认在Field()函数中允许,这里不建议在Field()函数中设置它的值为False。如果在字段上设置该参数值为False,Pydantic发现未强制执行的约束,会引发错误。

❑regex是一种校验规则,表示该字段参数值如果是字符串类型,则需遵循正则表达式验证约束规则。

❑repr如果为False,则该字段应从对象表示中隐藏,默认值为True。

❑extra是可以自定义的其他参数,比如显示在可视化文档中的example。”

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
from decimal import Decimal
from typing import Union, Optional, List

from pydantic import BaseModel, Field


class User(BaseModel):
    name: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo")
    age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12)
    password: str = Field(..., title='密码', description='密码需要长度大于6', gl=6, example=6)
    tax: Optional[float] = Field(None, example=3.2)

if __name__ == '__main__':
    user=User(name='xiaozhong',age=18,password='xxxxxxxxxxx')
    print(user.name)
    print(user.age)
    print(user.password)

# 输出结果
xiaozhong
18
xxxxxxxxxxx

5.2.9 自定义验证器

在某种场景下,有可能需要针对模型中的某个参数添加更多的自定义验证逻辑,Pydantic提供了一个validator装饰器对象。通过该装饰器,用户可以实现参数自定义验证机制.

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
from typing import Union, Optional, List

from pydantic import BaseModel, field_validator, ValidationError


class Person(BaseModel):
    username: str
    password: str

    # '*' 在这里是匹配任意字段
    @field_validator('*')
    def split(cls, v,):
        """如果传参是字符串,根据逗号切割成list"""
        if isinstance(v, str):
            return v.split(',')
        return v


if __name__ == '__main__':
    try:
        user = Person(username='xiaozhong', password='123456')
    except ValidationError as e:
        print(e.errors())
        print(e.json())
    else:
        print(user.username, user.password)

在这里插入图片描述

单独使用@field_validator重新对内置的password参数进行一次校验,其中定义的检验逻辑比较简单,主要是判断输出的密码长度是否符合限制条件。如果不符合,则直接抛出ValueError异常;如果符合,则直接返回当前校验参数模型的值。
需要注意,在上面的验证器中,被@field_validator装饰的password_rule()函数的第一个参数cls指向的是模型类本身,而不是实例化的对象,而第二个参数可随意输入,它可以表示当前被校验的对象。在校验逻辑内部抛出错误是通过ValueError的方式实现的。

5.2.10 自定义验证器优先级

通过@field_validator(“address”,check_fields=True)
自定义了验证器并实现了某个参数特定逻辑的校验,验证器内部逻辑是在模型完成输入参数类型的校验之后才执行的。

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
from typing import Dict

from pydantic import BaseModel, field_validator, ValidationError


class Person(BaseModel):
    username: str
    address: Dict

    @field_validator("address",check_fields=True)
    def adress_rule(cls, address):
        # 如果地址长度小于6,那么则返回
        if len(address) < 6:
            raise ValueError("地址长度不能小于6")
        elif len(address) > 12:
            raise ValueError("地址长度不能大于12")
        return address

if __name__ == '__main__':
    try:
        user = Person(username='xiaozhong', address='12345')
    except ValidationError as e:
        print(e.errors())
    else:
        print(user.username, user.address)
# 输出结果
(fastapi) fishyuu@FishyuudeMacBook-Pro chapter05 % /usr/bin/python3 /Users/fishyuu/2025_learn/fastapi_tutorial/chapter05/pydantic_validator_order/main.py
[{'type': 'dict_type', 'loc': ('address',), 'msg': 'Input should be a valid dictionary', 'input': '12345', 'url': 'https://errors.pydantic.dev/2.11/v/dict_type'}]

5.3 pydantic在fastapi中的应用

5.3.1 模型类和body的请求

可以通过定义pydantic数据模型来应对请求参数中提交的request body参数。使用模型绑定请求体参数的方式,完成参数绑定、解析及验证。

from fastapi import FastAPI
from pydantic import BaseModel, model_validator, Field

app = FastAPI()


class User(BaseModel):
    username: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo")
    age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12)
    password_old: str = Field(..., title='旧密码', description='密码需要长度大于6', min_length=6, example="oldpass")
    password_new: str = Field(..., title='新密码', description='密码需要长度大于6', min_length=6, example="newpass")

    @model_validator(mode='after')
    def check_passwords(self) -> 'User':
        if self.password_old == self.password_new:
            raise ValueError('New password must be different from old password')
        return self


@app.post("/user")
def read_user(user: User):
    return {
        'username': user.username,
        'password_old': user.password_old,
        'password_new': user.password_new,
    }


if __name__ == "__main__":
    import uvicorn
    import os

    app_module_name = os.path.basename(__file__).replace(".py", "")
    uvicorn.run(f"{app_module_name}:app", host='127.0.0.1', reload=True)

上面代码做了3件事情:

❑定义一个User模型。

❑在模型中通过Field定义相关字段属性的验证机制。

❑在模型类中使用根验证器对新旧密码做对比。

5.3.2 模型Config类和ORM转化

在pydantic模型类有一个Config类,他可以为pydanti模型扩展更多定制行为。对Config类的主要配置项进行具体说明。

❑title:表示指定生成JSON格式的标题(使用BaseModel.schema_json返回JSON字符串中的title)。

❑anystr_strip_whitespace:表示str类型的字符是否自动去除前面和后面存在的空格(默认值:False)。

❑anystr_lower:表示所有的str字符是否自动转换为小写,默认值为False,即不转换。

❑max_anystr_length:表示所有的str字符允许设置的最大长度,默认值为None。

❑min_anystr_length:表示所有的str字符允许设置的最小长度,默认值为0。

❑validate_all:表示是否验证字段的默认值,默认值为False,即不验证。

❑extra:表示在模型初始化期间是否忽略(“ignore”)、允许(“allow”)、禁止(“forbid”)等额外参数的传入。支持字符串,也可以直接使用Extra枚举对象,其他具体的配置项说明如下:

❍ignore:表示传递额外参数不会抛出异常,但是模型实例对象不会包含额外属性。

❍allow:表示允许传递额外参数,且模型实例对象可以获取额外属性。

❍forbid:表示不允许传递任何额外参数。

❑fields:表示当前模型类型包含字段的所有架构信息。

❑allow_mutation:表示模型字段参数的初始值是否允许被修改,它是一个全局配置模式。

❑use_enum_values:表示是否允许使用枚举的属性(非原始枚举)填充模型。

❑validate_assignment:表示是否对当前模型类属性的分配执行验证(默认值:False)。

❑allow_population_by_field_name:表示模型中是否允许使用字段名称来填充模型字段。

❑error_msg_templates:表示对应自定义错误消息模板。它可以覆盖默认消息模板。

❑orm_mode:表示是否允许从ORM生成模型。

❑schema_extra:表示自定义扩展/更新生成的JSON模式信息,一般在可视化交互文档中展示出来。

❑json_loads:用于在模型转换为JSON时自定义解码JSON的函数。

❑json_dumps:用于在模型中自定义编码JSON的函数。

❑json_encoders:用于在模型转换时自定义编码的方式。

❑underscore_attrs_are_private:表示是否所有非ClassVar下画线属性都将被视为私有,还是保持原样。

通常使用sqlalchemy查询具体记录,但是需要把查询结果转换为字典或json对象进行返回,通过config类中的配置项可以把orm模型类直接转换为pydantic模型,不再需要对orm模型做特殊处理,代码如下:

from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base  # 更新导入方式
from pydantic import BaseModel, Field

# ORM模型基类
Base = declarative_base()

# ORM模型类定义
class UserSqlalchemyOrmModel(Base):
    # 表名称
    __tablename__ = 'user'
    # 表字段
    id = Column(Integer, primary_key=True, nullable=False)  # 定义ID
    userid = Column(String(20), index=True, nullable=False, unique=True)  # 创建索引
    username = Column(String(32), index=True, unique=True)  # 用户名字段

# Pydantic模型类定义
class UserPydanticModel(BaseModel):
    id: int
    userid: str = Field(..., title='用户ID', description='用户ID字段需要长度大于6且小于等于20', max_length=20, min_length=6, example="0000001")
    username: str = Field(..., title='用户名称', description='用户名称字段需要长度大于6且小于等于32', max_length=32, min_length=6, example="0000001")

    class Config:
        # 表示可以从ORM中创建,没有这个会报错
        from_attributes = True

# 创建ORM类的对象
user_orm = UserSqlalchemyOrmModel(id=123, userid='1000001001', username='xiaozhong')

# 从ORM类的对象实例化UserPydanticModel的模型对象
user_pydantic = UserPydanticModel.model_validate(user_orm)
print(user_pydantic)
# 输出结果:id=123 userid='1000001001' username='xiaozhong'

网站公告

今日签到

点亮在社区的每一天
去签到