允许 pydantic 模型具有可选的空字段,如 v1

问题描述 投票:0回答:1

我最近从 Pydantic v1 升级到 v2。

因此,它让我更新了我的模型:

# OLD MODEL
class Tag(BaseModel):
    id: int
    name: str
    color: Optional[str]  # We didn't used to need to set a default value


# NEW MODEL
class Tag(BaseModel):
    id: int
    name: str
    color: Optional[str] = None  # Now we do

问题在于它更新了 OpenAPI 规范,破坏了我们基于此生成代码的其他应用程序:

# Old spec
Tag:
  title: Tag
  type: object
  required:
  - id
  - name
  properties:
    ...
    ...
    color:
      title: Color
      type: string
# New spec
Tag:
  title: Tag
  type: object
  required:
  - id
  - name
  - color            # Uh oh! Now it's required!
  properties:
    ...
    ...
    color:
      title: Color
      anyOf:          # Uh oh! We've got a weird type! I don't want null!
      - type: string
      - type: 'null'

这是一个问题,因为现在我们突然鼓励人们向我们发送

null
值,这与根本不发送值完全不同(在我看来)。

因此,为了解决这个问题,我发现我可以以不同的方式更新我的模型:

class Tag(BaseModel):
    id: int
    name: str
    color: str = None  # No longer optional!

# Now the openapi spec is perfect, like it used to be.
# color is not required, and does not accept null.

但是后来我遇到了响应的验证问题:

E fastapi.exceptions.ResponseValidationError: 2 validation errors:
E  {'type': 'string_type', 'loc': ('response', 'tag', 'color'),
E   'msg': 'Input should be a valid string', 'input': None,
E   'url': 'https://errors.pydantic.dev/2.5/v/string_type'}

端点:

@app.get(
    "/tags",
    response_model=List[src.schemas.tags.Tag],
    response_model_exclude_none=True,
):
    # Endpoint code

存在的问题

这里的问题是我不只有 1 个端点。我有大约 100 个端点,我不想为所有端点编写和维护自定义验证器。

我希望使用

app.openapi()
生成的 OpenAPI 规范相同,并且我还希望允许端点返回 null/none 而不是字符串。

这就是为什么我尝试了

response_model_exclude_none=True
,但没有成功。

  • 我想 避免使用架构
    anyOf string/null
  • 我希望我的运行时响应验证能够工作
fastapi openapi pydantic openapi-generator
1个回答
0
投票

我认为新行为是完全正确的,并且改进了 v1 中有些模糊的定义。如果一个值确实是可选的,则需要定义一个默认值。这完全符合Python的标准行为。注释

Optional[str]
相当于更明确的
Union[str, None]
,它明确允许
None
为有效值。我在这里能想到的最正确的解决方案是选择一个有意义的默认值:

from pydantic import BaseModel

class Tag(BaseModel):
    id: int
    name: str
    color: str = "red"

这应该将该字段声明为非必需字段,并且也不会破坏验证。此外,您还解决了当用户未提供该字段时默认使用哪个问题的问题。

所以我会投入工作并定义有意义的默认值。

我希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.