FastAPI 中的部分更新

Sae*_*ili 4 python sqlalchemy python-3.x pydantic fastapi

我想在 FastAPI 中实现支持部分更新的 put 或 patch 请求。官方文档真的很混乱,我不知道如何执行请求。(我不知道items文档中是否有此内容,因为我的数据将与请求的正文一起传递,而不是硬编码的字典)。

class QuestionSchema(BaseModel):
    title: str = Field(..., min_length=3, max_length=50)
    answer_true: str = Field(..., min_length=3, max_length=50)
    answer_false: List[str] = Field(..., min_length=3, max_length=50)
    category_id: int


class QuestionDB(QuestionSchema):
    id: int


async def put(id: int, payload: QuestionSchema):
    query = (
        questions
        .update()
        .where(id == questions.c.id)
        .values(**payload)
        .returning(questions.c.id)
    )
    return await database.execute(query=query)

@router.put("/{id}/", response_model=QuestionDB)
async def update_question(payload: QuestionSchema, id: int = Path(..., gt=0),):
    question = await crud.get(id)
    if not question:
        raise HTTPException(status_code=404, detail="question not found")

    ## what should be the stored_item_data, as documentation?
    stored_item_model = QuestionSchema(**stored_item_data)
    update_data = payload.dict(exclude_unset=True)
    updated_item = stored_item_model.copy(update=update_data)

    response_object = {
        "id": question_id,
        "title": payload.title,
        "answer_true": payload.answer_true,
        "answer_false": payload.answer_false,
        "category_id": payload.category_id,
    }
    return response_object

Run Code Online (Sandbox Code Playgroud)

我怎样才能完成我的代码以获得成功的部分更新?

Sae*_*ili 6

我在 FastAPI 的 Github 问题上得到了这个答案。

Optional您可以在基类上创建字段并创建一个QuestionCreate扩展QuestionSchema. 举个例子:

from typing import Optional

class Question(BaseModel):
    title: Optional[str] = None  # title is optional on the base schema
    ...

class QuestionCreate(Question):
   title: str  # Now title is required
Run Code Online (Sandbox Code Playgroud)

这里的cookiecutter 模板也提供了一些很好的见解。


cdr*_*per 6

在此发布此内容是为了那些正在寻找直观的解决方案来创建其 pydantic 模型的可选版本而无需重复代码的 Google 用户。

\n

假设我们有一个User模型,并且我们希望允许 PATCH 请求来更新用户。但是我们需要创建一个模式来告诉 FastApi 内容正文中的内容,特别是所有字段都是可选的(因为这是 PATCH 请求的本质)。我们无需重新定义所有字段即可做到这一点

\n
from pydantic import BaseModel\nfrom typing import Optional\n\n# Creating our Base User Model\nclass UserBase(BaseModel):\n   username: str\n   email: str\n   \n\n# And a Model that will be used to create an User\nclass UserCreate(UserBase):\n   password: str\n\n
Run Code Online (Sandbox Code Playgroud)\n

代码重复 \xe2\x9d\x8c

\n
class UserOptional(UserCreate):\n    username: Optional[str]\n    email: Optional[str]\n    password: Optional[str]\n
Run Code Online (Sandbox Code Playgroud)\n

一行 \xe2\x9c\x85

\n
# Now we can make a UserOptional class that will tell FastApi that all the fields are optional. \n# Doing it this way cuts down on the duplication of fields\nclass UserOptional(UserCreate):\n    __annotations__ = {k: Optional[v] for k, v in UserCreate.__annotations__.items()}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

注意:即使模型上的某个字段已经是可选的,由于可选在typing.Union[type passed to Optional, None]后台的性质,它也不会产生任何影响。

\n

IEtyping.Union[str, None] == typing.Optional[str]

\n
\n

如果您要多次使用它,您甚至可以将其变成一个函数:

\n
def convert_to_optional(schema):\n    return {k: Optional[v] for k, v in schema.__annotations__.items()}\n\nclass UserOptional(UserCreate):\n    __annotations__ = convert_to_optional(UserCreate)\n\n
Run Code Online (Sandbox Code Playgroud)\n