You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI结合Ormar使用ForwardRef时出现未定义错误求助

问题解决:Ormar多对多关系中的PydanticUndefinedAnnotation错误

错误根源分析

你的代码存在两个关键问题:

  1. User类重复定义email字段:同一个模型里出现两次email属性,会导致Pydantic解析模型时出错,同时干扰Ormar的ORM映射逻辑。
  2. ForwardRef处理不完整:虽然调用了User.update_forward_refs(),但多对多关系需要双向定义,且需确保更新引用时上下文包含完整的模型定义。

修正后的代码

import uuid
import datetime
import sqlalchemy
import databases
import ormar
from typing import ForwardRef

# 假设config已正确导入
database = databases.Database(config.database_url)
metadata = sqlalchemy.MetaData()

base_ormar_config = ormar.OrmarConfig(
    metadata=metadata,
    database=database,
)

ProjectRef = ForwardRef("Project")


class BaseModel(ormar.Model):
    ormar_config = base_ormar_config.copy(abstract=True)
    id: str = ormar.UUID(primary_key=True, default=uuid.uuid4, uuid_format="string")
    created_at: datetime.datetime = ormar.DateTime(server_default=sqlalchemy.func.now())


class User(BaseModel):
    ormar_config = base_ormar_config.copy(tablename="users")
    subscription: str = ormar.String(max_length=254, nullable=True)
    # 保留唯一且非空的email字段,删除重复定义
    email: str = ormar.String(max_length=244, nullable=False, unique=True)
    name: str = ormar.String(max_length=555, nullable=True)
    phone: str = ormar.String(max_length=555, nullable=True)
    company_name: str = ormar.String(max_length=555, nullable=True)
    occupation: str = ormar.String(max_length=555, nullable=True)
    # 多对多关系定义,使用ForwardRef
    projects = ormar.ManyToMany(ProjectRef)

class Project(BaseModel):
    ormar_config = base_ormar_config.copy(tablename="projects")
    owner: User = ormar.ForeignKey(User, name="owner_id")
    name: str = ormar.String(max_length=244, nullable=True)
    description: str = ormar.String(max_length=555, nullable=True)
    files: list[str] = ormar.JSON(default=list)
    # 添加多对多的反向关系(可选,但推荐保持关系双向)
    users = ormar.ManyToMany(User, related_name="projects")

# 同时更新两个模型的forward refs
User.update_forward_refs()
Project.update_forward_refs()

关键修改说明

  • 删除重复的email字段:保留nullable=False且unique=True的版本,符合用户邮箱唯一且必填的业务逻辑。
  • 添加反向多对多关系:在Project类中定义users = ormar.ManyToMany(User, related_name="projects"),确保关系双向可访问,帮助Ormar正确解析模型依赖。
  • 更新两个模型的forward refs:除了User,也要调用Project.update_forward_refs(),确保两个模型都能正确解析对方的引用。

替代简化方案(无需显式ForwardRef)

Ormar支持直接使用字符串形式的模型名称定义延迟引用,可省去显式创建ForwardRef的步骤,代码更简洁:

# 移除ProjectRef = ForwardRef("Project")这一行

class User(BaseModel):
    # ... 其他字段
    projects = ormar.ManyToMany("Project")  # 直接用字符串引用

class Project(BaseModel):
    # ... 其他字段
    users = ormar.ManyToMany(User, related_name="projects")

# 同样需要调用update_forward_refs
User.update_forward_refs()
Project.update_forward_refs()

内容的提问来源于stack exchange,提问作者Devon Ray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 09:12:36