FastAPI - 使用嵌套模型会产生 JSON 序列化错误

FastAPI - Using nested model gives JSON serialization error

我正在尝试在 POST 调用中使用嵌套模型。目标是在我的 Keycloak 实例中使用 API 创建一个用户,因此我按照文档创建了我需要的模型。

当我尝试使用我的 API 通过 Postman 创建用户时,fastAPI 给我以下错误:

Object of type Attributes is not JSON serializable

代码如下:

user.py

from pydantic import BaseModel


# TODO Error: Object of type Attributes is not JSON serializable.
class Attributes(BaseModel):
    locale: str
    phoneNumber: str

    class Config:
        orm_mode = True


class Credentials(BaseModel):
    value: str
    type: str

    class Config:
        orm_mode = True


class User(BaseModel):
    email: str
    username: str
    enabled: bool
    firstName: str
    lastName: str
    attributes: Attributes
    credentials: list[Credentials]

    class Config:
        orm_mode = True

创建_user.py

def create_new_keycloak_user(user: User):
    admin = keycloak_service.connect_to_keycloak_as_admin()
    try:
        body = vars(user)
        print(body)
        new_user = admin.create_user(body)
        return new_user
    except Exception as err:
        raise HTTPException(status_code=400, detail=f"User creation failed: {err}")

routing.py

# I also have tried without response_model=User

@router.post("/create-user", response_model=User)
async def create_new_user(user: User):
    create_user.create_new_keycloak_user(user)
    return user

当我尝试创建用户时在后端收到的正文:

{'email': 'jhondoe@mail.it', 'username': 'mverdi', 'enabled': True, 'firstName': 'Jhon', 'lastName': 'Doe', 'attributes': Attributes(locale='ITA', phoneNumber='+391234567891'), 'credentials': [Credentials(value='superpassword01', type='password')]}

我认为这与这个“畸形”有关JSON,如果你在之前的JSON中注意到我有

'attributes': Attributes(locale='ITA', phoneNumber='+391234567891'),

这显然不允许以正确的 JSON 格式出现。但是为什么我会收到这样的结果?

将 FastAPI 与 Python3.10 和 Pydantic

结合使用

我解决了。问题出在文件 create_user.py

我正在使用 vars() 转换我的用户对象,后者将我的用户转换为字典(这与 JSON 不同)但是我需要使用适当的 json FastAPI框架提供的编码器。

旧代码:

def create_new_keycloak_user(user: User):
    admin = keycloak_service.connect_to_keycloak_as_admin()
    try:
        body = vars(user)
        print(body)
        new_user = admin.create_user(body)
        return new_user
    except Exception as err:
        raise HTTPException(status_code=400, detail=f"User creation failed: {err}")

新代码:

def create_new_keycloak_user(user: User):
    admin = keycloak_service.connect_to_keycloak_as_admin()
    try:
        body = jsonable_encoder(user)
        admin.create_user(body)
    except Exception as err:
        raise HTTPException(status_code=400, detail=f"User creation failed: {err}")