【问题标题】:Including special character in Basemodel for Pydantic在 Pydantic 的 Basemodel 中包含特殊字符
【发布时间】:2021-08-13 02:38:00
【问题描述】:

我正在尝试使用包含“$”符号的键创建 Pydantic 基本模型。它看起来像这样:

class someModel(BaseModel):
    $something:Optional[str] = None

然后我得到SyntaxError: invalid syntax。 但我需要保留密钥名称$something 以在其他部分使用。在这种情况下有没有办法允许使用美元符号?

【问题讨论】:

  • 您能解释一下为什么属性名称上需要$ 符号吗?它不是一个有效的 Python 名称。
  • 谢谢,那是因为我需要将它传递给请求正文。我可以转换为字符串并将 $ 符号与其他服务通信,但我想知道应该如何处理这个问题。

标签: python fastapi pydantic


【解决方案1】:

您可以使用Field(alias=...) 来使用不同的(有效的)变量名。

from pydantic import BaseModel, Field

class SomeModel(BaseModel):
    something: Optional[str] = Field(alias="$something", default=None)

我还添加了默认值 None,因为您的代码中有它。

这是一个工作示例(编辑:更新以显示如果您以后需要使用它,如何获取变量名称的别名):

import logging
from typing import Optional
from fastapi import FastAPI, Request
from pydantic import BaseModel, Field

logging.basicConfig(level=logging.INFO, format="%(levelname)-9s %(asctime)s - %(name)s - %(message)s")
LOGGER = logging.getLogger(__name__)

app = FastAPI()


class SomeModel(BaseModel):
    something: Optional[str] = Field(alias="$something", default=None)


@app.post("/")
async def root(request: Request, parsed_body: SomeModel):

    # A dict of all the model fields and their properties
    LOGGER.info(f"SomeModel.__fields__: {SomeModel.__fields__}")

    # To get the alias of the variable name
    something_alias = SomeModel.__fields__["something"].alias
    LOGGER.info(f"something_alias: {something_alias}")

    # Edit: prefer to use "parsed_body_by_alias" than raw_body. Leaving here to show the difference.
    raw_body: bytes = await request.body()
    LOGGER.info(f"raw_body: {raw_body}")

    # Edit: This is better as you get validated / parsed values, including defaults if applicable.
    parsed_body_by_alias = parsed_body.dict(by_alias=True)
    LOGGER.info(f"parsed_body_by_alias: {parsed_body_by_alias}")

    # If you just want "something" instead of "$something"
    LOGGER.info(f"parsed_body: {parsed_body}")
    LOGGER.info(f"parsed_body.something: {parsed_body.something}")

    return 1


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8080)

如果您运行代码,则发送带有正文的 POST:

{"$something": "bar"}

你会看到类似的东西:

INFO      xxx - __main__ - SomeModel.__fields__: {'something': ModelField(name='something', type=Optional[str], required=False, default=None, alias='$something')}
INFO      xxx - __main__ - something_alias: $something
INFO      xxx - __main__ - raw_body: b'{"$something": "bar"}'
INFO      xxx - __main__ - parsed_body_by_alias: {'$something': 'bar'}
INFO      xxx - __main__ - parsed_body: something='bar'
INFO      xxx - __main__ - parsed_body.something: bar
INFO:     127.0.0.1:xxxxx - "POST / HTTP/1.1" 200 OK

【讨论】:

  • 非常感谢!我学会了新方法:) 但是有没有不使用请求的方法?最好,我只想将 parsed_body 与集合 alias 一起用于 something
  • 不用担心,是的,我只是编辑了我的答案以显示替代方案。根据您使用它的方式,您可能希望通过在模型的字段中查找它来获取 something 的别名,或者您可能只想要一个带有别名的已解析负载的字典。编辑后的答案现在说明了这些不同的方法。
猜你喜欢
  • 2014-10-16
  • 2020-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 1970-01-01
相关资源
最近更新 更多