首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >FastAPI - "TypeError: issubclass() arg 1必须是一个带有模块化导入的类“

FastAPI - "TypeError: issubclass() arg 1必须是一个带有模块化导入的类“
EN

Stack Overflow用户
提问于 2022-11-07 12:24:38
回答 1查看 93关注 0票数 1

在使用FastAPI和SQLModel进行模块化导入时,如果打开/docs,将得到以下错误:

TypeError: issubclass() arg 1必须是一个

  • Python 3.10.6
  • 化脓性1.10.2
  • fastapi 0.85.2
  • sqlmodel模型0.0.8
  • macOS 12.6

这里是一个可重复的例子。

user.py

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
from sqlmodel import SQLModel, Field

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

main.py

代码语言:javascript
运行
复制
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的教程。如果我把模型放在同一个文件里,一切都很好。由于我的实际模型相当复杂,所以我需要依赖模块导入。

回溯:

代码语言:javascript
运行
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-07 21:02:02

TL;DR

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

解释

因此,这实际上要复杂得多,我还不太确定,为什么在文档中没有提到这一点。也许我遗漏了什么。不管怎样..。

如果您遵循跟踪,您将看到错误发生,因为在pydantic.schemafield_singleton_schema函数的第921行中,执行了一次检查,以查看issubclass(field_type, BaseModel)和在这一点上field_type是否实际上不是type实例。

调试表明,当生成User模型的模式并处理bought_items字段时,就会发生这种情况。此时,注释将被处理,List的类型参数仍然是到Item正向参考。这意味着它不是实际的Item类本身。这就是传递给issubclass并导致错误的原因。

这是一个相当常见的问题,在处理Pydantic模型之间的递归或循环关系时,这就是为什么它们如此友好地提供了一种特殊的方法。它将在文档的延迟注解部分中解释。这个方法是update_forward_refs,顾名思义,它是用来解析前向引用的。

在这种情况下,需要使用更新的命名空间来解析Item引用,这是很棘手的。要做到这一点,您需要,实际上,在作用域中有真正的Item类,因为这是该名称空间中需要的。你在哪里做这件事并不重要。例如,您可以将User模型导入到您的item模块中,并将其称为那里(显然低于Item的定义):

代码语言:javascript
运行
复制
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)

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

代码语言:javascript
运行
复制
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转义。您只需在from .item import Item中执行user.py,并将实际的类作为bought_items: list[Item]放在注释中。但是,我假设您简化了实际用例,并且简单地忘记了包括循环依赖。

也许我遗漏了一些东西,这里的其他人可以找到一种方法来调用update_forward_refs,而不需要显式地提供Item,但是这种方式肯定会起作用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74346565

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档