gpt4 book ai didi

python - FastAPI - "TypeError: issubclass() arg 1 must be a class"模块化导入

转载 作者:行者123 更新时间:2023-12-02 01:26:49 51 4
gpt4 key购买 nike

当使用 FastAPI 和 SQLModel 进行模块化导入时,如果我打开/docs,我会收到以下错误:

TypeError: issubclass() arg 1 must be a class

  • python 3.10.6
  • 华丽的 1.10.2
  • fastapi 0.85.2
  • sql模型0.0.8
  • macOS 12.6

这是一个可重现的例子。

用户.py

from typing import List, TYPE_CHECKING, Optional
from sqlmodel import SQLModel, Field

if TYPE_CHECKING:
from item import Item

class User(SQLModel):
id: int = Field(default=None, primary_key=True)
age: Optional[int]
bought_items: List["Item"] = []

item.py

from sqlmodel import SQLModel, Field

class Item(SQLModel):
id: int = Field(default=None, primary_key=True)
price: float
name: str

主.py

from fastapi import FastAPI

from user import User

app = FastAPI()

@app.get("/", response_model=User)
def main():
return {"message": "working just fine"}

我遵循了 sqlmodel https://sqlmodel.tiangolo.com/tutorial/code-structure/#make-circular-imports-work 的教程.如果我将模型放在同一个文件中,一切正常。由于我的实际模型非常复杂,因此我需要依赖模块化导入。

回溯:

Traceback (most recent call last):
File "/Users/felix/opt/anaconda3/envs/fastapi_test/lib/python3.10/site-packages/fastapi/utils.py", line 45, in get_model_definitions
m_schema, m_definitions, m_nested_models = model_process_schema(
File "pydantic/schema.py", line 580, in pydantic.schema.model_process_schema
File "pydantic/schema.py", line 621, in pydantic.schema.model_type_schema
File "pydantic/schema.py", line 254, in pydantic.schema.field_schema
File "pydantic/schema.py", line 461, in pydantic.schema.field_type_schema
File "pydantic/schema.py", line 847, in pydantic.schema.field_singleton_schema
File "pydantic/schema.py", line 698, in pydantic.schema.field_singleton_sub_fields_schema
File "pydantic/schema.py", line 526, in pydantic.schema.field_type_schema
File "pydantic/schema.py", line 921, in pydantic.schema.field_singleton_schema
File "/Users/felix/opt/anaconda3/envs/fastapi_test/lib/python3.10/abc.py", line 123, in __subclasscheck__
return _abc_subclasscheck(cls, subclass)
TypeError: issubclass() arg 1 must be a class

最佳答案

长话短说

您需要在 OpenAPI 设置之前调用 User.update_forward_refs(Item=Item)


解释

所以,这实际上有点棘手,我还不太确定,为什么文档中没有提到这一点。也许我错过了什么。无论如何...

如果您跟踪回溯,您会看到错误发生是因为在 field_singleton_schema 函数中的 pydantic.schema 的第 921 行执行检查以查看是否issubclass(field_type, BaseModel) 并且此时 field_type 实际上不是 type 实例。

一些调试表明,当正在生成 User 模型的架构并且正在处理 bought_items 字段时,就会发生这种情况。此时注释被处理并且 List 的类型参数仍然是 forward referenceItem。这意味着它不是实际的 Item 类本身。这就是传递给 issubclass 并导致错误的内容。

在处理 Pydantic 模型之间的递归或循环关系时,这是一个相当普遍的问题,这就是为什么他们非常友好地为此提供了一种特殊的方法。在 Postponed annotations 中进行了解释文档的一部分。该方法是 update_forward_refs,顾名思义,它用于解析前向引用。

在这种情况下棘手的是,您需要为其提供更新的命名空间以解析 Item 引用。为此,您需要实际上在作用域中拥有真正的Item 类,因为那是该命名空间中需要的东西。你在哪里做并不重要。例如,您可以将 User 模型导入到您的 item 模块中并在那里调用它(显然在 Item 的定义下方):

from sqlmodel import SQLModel, Field

from .user import User

class Item(SQLModel):
id: int = Field(default=None, primary_key=True)
price: float
name: str

User.update_forward_refs(Item=Item)

但该调用需要在尝试设置该架构之前发生。因此,您至少需要在 main 模块中导入 item 模块:

from fastapi import FastAPI

from .user import User
from . import item

api = FastAPI()

@api.get("/", response_model=User)
def main():
return {"message": "working just fine"}

此时,拥有一个仅包含模型模块的子包并将所有模块导入到该子包的 __init__.py 中可能会更简单。

我给出将 User.update_forward_refs 调用放在 Item 定义下方的示例的原因是,当您实际拥有循环关系时,这些情况通常会发生,例如,如果您的 Item 类有一个 users 字段,其类型为 list[User]。然后,您无论如何都必须在那里导入 User,并且还不如只更新那里的引用。

你的具体例子中,你实际上有任何循环依赖,所以严格来说没有必要TYPE_CHECKING转义.您可以简单地在 user.py 中执行 from .item import Item 并将实际类作为 bought_items: list[Item] 放在注释中。但我假设您简化了实际用例,只是忘记了包含循环依赖。


也许我遗漏了一些东西,这里的其他人可以找到一种方法来调用 update_forward_refs 而无需显式提供 Item,但这方法应该绝对有效。

关于python - FastAPI - "TypeError: issubclass() arg 1 must be a class"模块化导入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74346565/

51 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com