如何使用字段别名而不是 FastAPI 中的名称返回 Pydantic 模型?

use*_*986 4 python alias pydantic fastapi

我的 FastAPI 调用未以正确的模型格式返回数据Response。它以数据库模型格式返回数据。

我的数据库模型:

class cat(DBConnect.Base):
     __tablename__ = 'category'
     __table_args__ = {"schema": SCHEMA}
     cat_id = Column('cat_id',UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
     cat_desc = Column('cat_desc', TEXT, nullable=True)
     cat_h__l_name = Column('cat_h_l_name', TEXT, nullable=True)
Run Code Online (Sandbox Code Playgroud)

我的 Pydantic 模型:

class CamelModel(BaseModel):
    class config:
        alias_generator = to_camel
        allow_population_by_field_name = True

class cat(CamelModel):
    cat_id =Field(alais='CatID', readonly=True)
    cat_description =Field(alias='CatDescription')
    cat_h__l_name = Field(alias='CatName')
     
    class config:
       orm_mode= True
Run Code Online (Sandbox Code Playgroud)

我的 API 调用:

@router.patch('/cat/{id}/', response_model = 'cat')
def update_cat(response= Response, params: updatecat = Depends(updatecat)):
    response_obj = { resonse_code: status.HTTP_200_OK, 
    response_obj : {}    
    }
    
    response_obj = session.query() # It is returning the correct data from the database
    response.status_code = response_obj['response_code']
    
    return JSONResponse(response_obj['response_obj'], status_code = response_obj['response_code'])
Run Code Online (Sandbox Code Playgroud)

获取以下格式的响应:

     cat_id = 'some uuid'
     cat_desc = 'desc'
     cat_h__l_name = 'some h_l_name'
Run Code Online (Sandbox Code Playgroud)

但我希望回复采用以下格式:

CatID = 'some uuid'
CatDescription ='' some description'
CatName = 'Some cat name'
Run Code Online (Sandbox Code Playgroud)

这段代码没有给出任何错误(我已经输入了它,所以可能有一些缩进或拼写错误)。唯一的问题是 API 不以正确的格式返回数据。我已经坚持了一段时间了。我是 FastAPI 新手。请帮我。

Chr*_*ris 5

Field要使用别名而不是名称从 API 端点返回 Pydantic 模型,您可以添加response_model_by_alias=True到端点的装饰器。文档中提到了这一点。使用response_model_by_alias=False会产生相反的效果。下面的示例使用模型的配置alias_generator自动生成字段的别名。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


def to_pascal(string: str) -> str:
    return ''.join(word.capitalize() for word in string.split('_'))

class Item(BaseModel):
    name: str
    language_code: str
    
    class Config:
        alias_generator = to_pascal
        allow_population_by_field_name = True    
            

fake_db = [
    Item(Name='foo', LanguageCode='en'),
    Item(Name='bar', LanguageCode='fr')
]


@app.get('/item/{item_id}', response_model=Item, response_model_by_alias=True)
def create_item(item_id: int):
    return fake_db[item_id]
Run Code Online (Sandbox Code Playgroud)

Pydantic V2alias_generator中,您可以在类中使用ConfigDict,如文档中所示。Pydantic 提供了三个内置别名生成器:to_pascalto_camelto_snake。此外,在 v2.0 中,allow_population_by_field_name配置设置更改为populate_by_name. 此设置指示是否可以通过 model 属性给定的名称以及alias来填充别名字段。默认为False.

from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_pascal

class Item(BaseModel):
    model_config = ConfigDict(alias_generator=to_pascal, populate_by_name=True)
    name: str
    language_code: str
Run Code Online (Sandbox Code Playgroud)

如果想Field在不使用 的情况下创建别名alias_generator,可以按如下方式实现:

from pydantic import BaseModel, ConfigDict, Field

class Item(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    name: str = Field(..., alias='Name')
    language_code: str = Field(..., alias='LanguageCode')
Run Code Online (Sandbox Code Playgroud)

如果您使用alias_generator, 以及alias在 上指定Field, 则默认情况下alias优先于生成的别名

另外,正如 Pydantic文档中所解释的:

alias参数用于验证 序列化 。如果要分别使用不同的别名进行验证序列化,可以使用 和参数,这仅适用于各自的用例。validation_aliasserialization_alias

如果alias一起使用validation_aliasserialization_alias同时使用,则将validation_alias优先于alias验证,并serialization_alias 优先于alias序列化。

您还可以设置alias_priority一个字段来更改此行为。

使用返回 Pydantic 模型JSONResponse

还应该注意的是,您似乎从 API 端点返回的是JSONResponsePydantic 模型,而不是 Pydantic 模型;因此,设置response_model_by_alias=True不会有任何效果。因此,您可以使用 Pydantic 的方法将模型转换为字典model.dict(...)请注意,在 Pydantic V2 中,此方法已被 替换model.model_dump(...)),并将by_alias参数设置为True

附带说明一下,如果您有无法序列化的数据类型(例如、等),则在不先将Pydantic 模型转换JSONResponsedict为 a的情况下,您不能将其放入 a 中。对于这些情况,您可以使用来转换数据,然后再将其传递给响应。这将确保不可序列化的对象将被转换为.datetimeUUIDjsonable_encoderjsonable_encoderstr

from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder

@app.get('/item/{item_id}')
def create_item(item_id: int):
    return JSONResponse(jsonable_encoder(fake_db[item_id].model_dump(by_alias=True)), status_code=200)
Run Code Online (Sandbox Code Playgroud)