fastapi: 接口返回字典和返回JSONResponse的区别

一,返回字典和返回JSONResponse区别:

这是 FastAPI 底层的一个核心设计机制。

简单来说:当直接返回字典时,FastAPI 会帮你做“序列化加过滤”的脏活;
而当你使用 JSONResponse() 时,你等于绕过了 FastAPI 的安全代理,强行把一个包含数据库 ORM 对象的原生字典扔给了底层的 JSON 编码器。

标准的 Python json.dumps() 只能识别字典、列表、字符串、数字等基础类型。
它看到 <User object> 时一脸懵逼,不知道该怎么把它转成 JSON 文本,于是抛出错误:

 

TypeError: Object of type User is not JSON serializable(User 类型对象无法被 JSON 序列化)

 

表格:

image

二,代码:

# 1. 定义一个泛型变量 T,代表 data 字段可能接入的任何 Pydantic 模型
T = TypeVar("T")

# 输出给前端的用户信息(安全公开,不含密码,包含只读字段)
class UserResponse(BaseModel):
    id: int = Field(..., description="用户的唯一ID")
    username: str = Field(..., description="用户名")
    nickname: str = Field(..., description="用户昵称")

    class Config:
        from_attributes = True
        json_schema_extra = {
            "example": {"id": 1, "username": "alex_green", "nickname": "alex@example.com"}
        }


# 这是你需要补上的分页响应模型
class UserListPageResponse(BaseModel, Generic[T]):
    total: int
    items: List[T] # 核心:这里告诉 Pydantic,items 里面才是用户列表

# 2. 统一定义最外层的结构
class BaseResponse(BaseModel, Generic[T]):
    code: int = 200
    msg: str = "success"
    data: Optional[T] = None  # data 可以是任意类型 T

@router.get("/all2", response_model=BaseResponse[UserListPageResponse[UserResponse]], summary="获取商品和用户数据")
async def get_all_users2(request: Request,
                        prod_data: Annotated[UserListForm, Query()],
                           db: AsyncSession = Depends(get_db)):
    # 参数
    page = prod_data.page
    page_size = prod_data.page_size

    # 使用 func.count().over() 作为一个隐藏列
    stmt = (
        select(User, func.count().over().label("total_count"))
        .where(User.status == 1)
        .offset((page - 1) * page_size)
        .limit(page_size)
    )

    result = await db.execute(stmt)

    # 因为多查了一个 count 列,result 出来的每一行是一个元组 (User对象, total_count值)
    rows = result.all()

    # 解析结果
    if not rows:
        return {"total": 0, "page": page, "size": page_size, "items": []}

    # 无论哪一行,对应的 total_count 都是一样的,取第一行的即可
    total = rows[0].total_count
    items = [row.User for row in rows]


    raw_data = {
            "code": 200, "msg": "用户信息修改成功", "data": {
            "items": items,
            "total": total,
            }
        }
    '''
    # 核心:用 jsonable_encoder 预处理,把 User 对象转为字典
    safe_data = jsonable_encoder(raw_data)

    return JSONResponse(
        status_code=200, content=safe_data
    )
    '''
    return raw_data

 

 

三,测试效果:

直接返回JsonResponse()时,如果其中包含有object,则不能做json序列化,此时会报错,

raise TypeError(f'Object of type {o.__class__.__name__} '

TypeError: Object of type User is not JSON serializable,

使用JsonResponse的返回,可以看到response_model失效了,连password都显示出来了

image

直接返回字典时正常返回

image

 
 
 
 
 

 

posted @ 2026-07-24 20:05  刘宏缔的架构森林  阅读(2)  评论(0)    收藏  举报