FastAPI未能识别请求体中的字段。

huangapple go评论75阅读模式
英文:

FastAPI not recognising field in Request body

问题

我在创建的FastAPI应用中遇到了一个问题。我有一个用于创建新用户日历的路由,我目前正在尝试进行测试。

路由

# 添加用户日历
@router.post("", response_model=schemas.UserCalendar)
async def add_user_calendar(
    user_calendar: schemas.UserCalendarBase,
    current_user: schemas.User = Depends(deps.get_current_active_user),
    db: Session = Depends(deps.get_db),
    parent_slot: schemas.ParentSlot = None
):
    return usercalendar.add_user_calendar(user_calendar,
                                          current_user,
                                          db,
                                          parent_slot)

辅助函数

# 生成用户日历
def generate_user_calendar(
    account_id,
    calendar_name = "offline_test",
    calendar_id = "test_calendar_id",
    timezone = "Europe/London"
):
    return  {
        "account_id": account_id,
        "calendar_name": calendar_name,
        "calendar_id": calendar_id,
        "timezone": timezone
    }

# 创建用户日历
def create_user_calendar(user_calendar, headers):
    return requests.post(API_ENDPOINT + "/calendar",
                         headers=headers,
                         json=user_calendar)

模式

class UserCalendarBase(BaseModel):

    account_id: int
    calendar_name: str
    calendar_id: Union[str, None]
    timezone: str

    class Config:
        orm_mode = True

当我生成日历并调用create_user_calendar进行创建时,服务器端出现错误:

请求主体的验证错误1 - > user_calendar字段是必需的(type=value_error.missing)

如果我修改辅助函数以在顶层包含"user_calendar",则可以运行,例如:

# 生成用户日历
def generate_user_calendar(
    account_id,
    calendar_name = "offline_test",
    calendar_id = "test_calendar_id",
    timezone = "Europe/London"
):
    return  {
        "user_calendar" : {
            "account_id": account_id,
            "calendar_name": calendar_name,
            "calendar_id": calendar_id,
            "timezone": timezone
        }
    }

然而,在其他路由中,我无需添加此顶层字段。

例如:

# 生成用户账户辅助函数
def generate_user_account(
    user_id,
    account_type = "online",
    account_email = str(get_datetime_now_iso()) + "@email.com",
    account_provider = "google",
    used_for="PERSONAL"
):
    return {
        "user_id": user_id,
        "account_type": account_type,
        "account_email": account_email,
        "account_provider": account_provider, 
        "used_for": used_for
    }

# 创建用户账户辅助函数
def create_user_account(payload, headers):
    return requests.post(API_ENDPOINT + "/account",
                         headers=headers,
                         json=payload)

# 用户创建/注册路由
@router.post("/", response_model=schemas.User)
def create_user(
    user_to_create: schemas.UserCreate,
    db: Session = Depends(deps.get_db)
):
    return user.create_user(db=db, user=user_to_create)

# 模式
class UserBase(BaseModel):
    username: str
    email: str
    timezone: str

class UserCreate(UserBase):
    password: str

这是我做错了的吗?这似乎是我创建的唯一一个遇到此问题的路由。我显然已经找到了解决办法,但这意味着我需要以与其他路由不一致的方式处理此路由,即在请求中添加字段名,而其他路由似乎只是识别模式并完成工作。谢谢

英文:

I'm having an issue with a FastAPI app I'm creating. I have a route to create a new user calendar which I'm currently trying to test.

Route

# Add User Calendar
@router.post("", response_model=schemas.UserCalendar)
async def add_user_calendar(
    user_calendar: schemas.UserCalendarBase,
    current_user: schemas.User = Depends(deps.get_current_active_user),
    db: Session = Depends(deps.get_db),
    parent_slot: schemas.ParentSlot = None
):
    return usercalendar.add_user_calendar(user_calendar,
                                          current_user,
                                          db,
                                          parent_slot)

Helper Function

# generate a user calendar
def generate_user_calendar(
    account_id,
    calendar_name = "offline_test",
    calendar_id = "test_calendar_id",
    timezone = "Europe/London"
):
    return  {
        "account_id": account_id,
        "calendar_name": calendar_name,
        "calendar_id": calendar_id,
        "timezone": timezone
    }

# create a user calendar
def create_user_calendar(user_calendar, headers):
    return requests.post(API_ENDPOINT + "/calendar",
                         headers=headers,
                         json=user_calendar)

Schema

class UserCalendarBase(BaseModel):

    account_id: int
    calendar_name: str
    calendar_id: Union[str, None]
    timezone: str

    class Config:
        orm_mode = True

When I generate a calendar and then call create_user_calendar to create it I get an error on the server side:

1 validation error for Request body -> user_calendar field required (type=value_error.missing)

If I amend the helper function to include "user_calendar" at the top level then it works, e.g.

# generate a user calendar
def generate_user_calendar(
    account_id,
    calendar_name = "offline_test",
    calendar_id = "test_calendar_id",
    timezone = "Europe/London"
):
    return  {
        "user_calendar" : {
            "account_id": account_id,
            "calendar_name": calendar_name,
            "calendar_id": calendar_id,
            "timezone": timezone
        }
    }

In other routes though I have not had to add this top level field.

For example:

# generate a user account helper function
def generate_user_account(
    user_id,
    account_type = "online",
    account_email = str(get_datetime_now_iso()) + "@email.com",
    account_provider = "google",
    used_for="PERSONAL"
):
    return {
        "user_id": user_id,
        "account_type": account_type,
        "account_email": account_email,
        "account_provider": account_provider, 
        "used_for": used_for
    }

# create a user account helper function
def create_user_account(payload, headers):
    return requests.post(API_ENDPOINT + "/account",
                         headers=headers,
                         json=payload)

# User creation / registration route
@router.post("/", response_model=schemas.User)
def create_user(
    user_to_create: schemas.UserCreate,
    db: Session = Depends(deps.get_db)
):
    return user.create_user(db=db, user=user_to_create)

# schemas
class UserBase(BaseModel):
    username: str
    email: str
    timezone: str

class UserCreate(UserBase):
    password: str

Is this something that I've done wrong somewhere? It seems to be the only route I've created that I've encountered this issue. I've obviously got the fix but it means that I need to work with this route in an inconsistent manner to the others, i.e. adding the field name to the request where the others just seem to recognise the schema and do the work.

Thanks

答案1

得分: 1

add_user_calendar端点中,您期望有几个Pydantic对象(即user_calendarcurrent_userparent_slot)。这意味着这三个对象将被解释为请求主体,这显然没有意义。

解决方法是创建一个单一的Pydantic模型,该模型接受端点所需的所有字段(例如,您可以称其为AddUserRequest)。

请注意,在您的另一个示例create_user中,只接收一个Pydantic模型,因此不存在混淆。

英文:

In the endpoint add_user_calendar you are expecting several Pydantic objects (i.e., user_calendar, current_user and parent_slot). This means that the three of them will be interpreted as requests bodies, which makes little sense.

The solution would be to create a single Pydantic model that takes all the fields needed by the endpoint (you could call it, e.g., AddUserRequest).

Notice that in your other example, create_user, only one Pydantic model is received, and therefore the confusion doesn't exist.

huangapple
  • 本文由 发表于 2023年5月13日 14:56:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76241459.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定