SQLAlchemy模型字段类型标注及关联关系类型疑问
SQLAlchemy模型类型标注指南
一、基础字段的类型标注
SQLAlchemy 2.0+官方推荐使用Mapped和mapped_column组合做类型标注,这能准确映射数据库列对应的Python类型,同时让类型检查工具(如mypy、Pyright)正确识别字段的实际取值类型,而非Column对象本身。
修正你的Email模型示例:
from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy import String, ForeignKey import uuid from sqlalchemy.dialects.postgresql import UUID class Email(Model): __tablename__ = 'emails' name: Mapped[str] = mapped_column(String, nullable=False) sender: Mapped[str] = mapped_column(String, default=default_sender, nullable=False) subject: Mapped[str] = mapped_column(String, nullable=False) html: Mapped[str] = mapped_column(String, nullable=False) template_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey('templates.id'), index=True, )
Mapped[T]中的T就是你实际存取时用到的Python基础类型(如str、uuid.UUID)mapped_column是Column的类型安全封装,用来定义数据库列的属性
二、可空字段的标注方式
正确写法是Mapped[Optional[T]],因为nullable=True表示字段取值可以为None,而非整个列对象为None。
示例:
# 可空的字符串字段 description: Mapped[Optional[str]] = mapped_column(String, nullable=True)
- 不要用
Optional[Column[str]],这会被类型检查器误解为"列对象本身可能不存在",不符合ORM模型的定义逻辑。
三、关联关系的类型标注
关联关系的标注要根据lazy参数的取值调整,不同lazy会返回不同类型的结果:
1. 默认lazy='select'(即时加载)
- 一对多关系:返回列表,标注为
Mapped[list[关联模型]] - 一对一关系:返回单个对象(或None),标注为
Mapped[Optional[关联模型]](如果可空)
示例:
class Foo(Model): # 一对多关联Bar bars: Mapped[list[Bar]] = relationship('Bar', order_by=Bar.created_at.desc())
2. lazy='dynamic'(动态查询)
此时访问关联属性会返回一个Query对象(同步)或AsyncQuery(异步),需要标注对应的查询类型:
from sqlalchemy.orm import Query class Foo(Model): # ...其他字段 bar: Mapped[Query[Bar]] = relationship( 'Bar', order_by="desc(Bar.created_at)", lazy='dynamic', )
异步场景替换为AsyncQuery:
from sqlalchemy.ext.asyncio import AsyncQuery class Foo(Model): bar: Mapped[AsyncQuery[Bar]] = relationship( 'Bar', order_by="desc(Bar.created_at)", lazy='dynamic', )
3. lazy='joined'/'selectin'等其他加载方式
这类加载方式最终返回实体对象/列表,标注方式和默认lazy='select'一致,因为它们只是加载策略不同,返回值类型不变。
内容的提问来源于stack exchange,提问作者wwnnbb
相关产品推荐
相关产品推荐

