文章目录
- 这是最常见的问题。在旧版写法中,模型属性被定义为 Column 对象,例如: id = Column(Integer, primary_key=True) 对于静态分析工具(如 Pyright),id 的类型是 Column[Integer]。然而,当你实例化模型对象访问 user.id 时,其实际值是 int 类型。 当你尝试将 user.id 传递给一个期望 int 的函数时,Pyright 会报错: Argument of type “Column[Integer]” cannot be assigned to parameter of type “int” Mapped 解决了这个问题。它明确告诉类型检查器,虽然我们在类定义中使用了描述符,但在实例中该属性表现为指定的 Python 类型。
- 由于类型明确,现代 IDE(如 VS Code, PyCharm)能更准确地提供代码补全和错误提示。例如,定义为 Mapped[str | None] 的字段,IDE 会提示你该字段可能为 None。
- 旧写法 (Legacy): from sqlalchemy import Column, Integer, String class User(Base): __tablename__ = “user” id = Column(Integer, primary_key=True) name = Column(String(50), nullable=False) email = Column(String(100)) 新写法 (Modern – SQLAlchemy 2.0+): from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy import String from typing import Optional class User(Base): __tablename__ = “user” # Mapped[int] 告诉类型检查器:实例中的 id 是 int 类型 # mapped_column(…) 定义了数据库列的属性 id: Mapped[int] = mapped_column(primary_key=True) # nullable=False 是默认的,对应 Mapped[str] name: Mapped[str] = mapped_column(String(50)) # Optional[str] 或 str | None 对应 nullable=True email: Mapped[Optional[str]] = mapped_column(String(100))
- 旧写法: import uuid from sqlalchemy.dialects.postgresql import UUID from sqlalchemy import Column, DateTime, func class Document(Base): id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) created_at = Column(DateTime(timezone=True), server_default=func.now()) 新写法: import uuid from datetime import datetime from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.dialects.postgresql import UUID from sqlalchemy import DateTime, func class Document(Base): # 明确指定 id 是 uuid.UUID 类型 id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 明确指定 created_at 是 datetime 类型 created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
- 旧写法: from sqlalchemy import ForeignKey from sqlalchemy.orm import relationship class Post(Base): user_id = Column(Integer, ForeignKey(“user.id”)) user = relationship(“User”) 新写法: from sqlalchemy import ForeignKey from sqlalchemy.orm import Mapped, mapped_column, relationship class Post(Base): user_id: Mapped[int] = mapped_column(ForeignKey(“user.id”)) # 这里的 relationship 也支持 Mapped 类型 user: Mapped[“User”] = relationship()
目录
- 简介
- 解决的问题
- 1. 静态类型检查报错
- 2. IDE 智能感知
- 用法对比
- 1. 基本字段
- 2. 复杂类型 (UUID, DateTime)
- 3. 外键与关系
- 关键点总结
在 SQLAlchemy 1.4 和 2.0 中,ORM(对象关系映射)引入了一种新的声明式映射系统,核心组件是 Mapped 类型注解和 mapped_column 构造函数。这种新风格旨在提供更好的 Python 类型提示(Type Hinting)支持,解决旧版 Column 写法在静态代码分析(如 Pyright, MyPy)和 IDE 自动补全方面的问题。
这是最常见的问题。在旧版写法中,模型属性被定义为 Column 对象,例如:
id = Column(Integer, primary_key=True)
对于静态分析工具(如 Pyright),id 的类型是 Column[Integer]。然而,当你实例化模型对象访问 user.id 时,其实际值是 int 类型。
当你尝试将 user.id 传递给一个期望 int 的函数时,Pyright 会报错:
Argument of type “Column[Integer]” cannot be assigned to parameter of type “int”
Mapped 解决了这个问题。它明确告诉类型检查器,虽然我们在类定义中使用了描述符,但在实例中该属性表现为指定的 Python 类型。
由于类型明确,现代 IDE(如 VS Code, PyCharm)能更准确地提供代码补全和错误提示。例如,定义为 Mapped[str | None] 的字段,IDE 会提示你该字段可能为 None。
旧写法 (Legacy):
from sqlalchemy import Column, Integer, String
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
email = Column(String(100))
新写法 (Modern – SQLAlchemy 2.0+):
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import String
from typing import Optional
class User(Base):
__tablename__ = "user"
# Mapped[int] 告诉类型检查器:实例中的 id 是 int 类型
# mapped_column(...) 定义了数据库列的属性
id: Mapped[int] = mapped_column(primary_key=True)
# nullable=False 是默认的,对应 Mapped[str]
name: Mapped[str] = mapped_column(String(50))
# Optional[str] 或 str | None 对应 nullable=True
email: Mapped[Optional[str]] = mapped_column(String(100))
旧写法:
import uuid
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy import Column, DateTime, func
class Document(Base):
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
created_at = Column(DateTime(timezone=True), server_default=func.now())
新写法:
import uuid
from datetime import datetime
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy import DateTime, func
class Document(Base):
# 明确指定 id 是 uuid.UUID 类型
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
# 明确指定 created_at 是 datetime 类型
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
旧写法:
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class Post(Base):
user_id = Column(Integer, ForeignKey("user.id"))
user = relationship("User")
新写法:
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
class Post(Base):
user_id: Mapped[int] = mapped_column(ForeignKey("user.id"))
# 这里的 relationship 也支持 Mapped 类型
user: Mapped["User"] = relationship()
- 导入: 使用
from sqlalchemy.orm import Mapped, mapped_column。
- 类型注解: 必须为每个列添加 Python 类型注解(如
: Mapped[int])。
- Nullable:
Mapped[str] 隐含 nullable=False。
Mapped[Optional[str]] 或 Mapped[str | None] 隐含 nullable=True。
- SQL 类型: 在
mapped_column() 中通过第一个参数指定 SQL 类型(如 String(50)),如果类型可以从 Python 类型推断(如 int -> Integer),则可以省略。但对于 String(需要长度)或 UUID 等特殊类型,通常还是需要指定。
from sqlalchemy.orm import Mapped, mapped_column。: Mapped[int])。Mapped[str]隐含nullable=False。Mapped[Optional[str]]或Mapped[str | None]隐含nullable=True。
mapped_column() 中通过第一个参数指定 SQL 类型(如 String(50)),如果类型可以从 Python 类型推断(如 int -> Integer),则可以省略。但对于 String(需要长度)或 UUID 等特殊类型,通常还是需要指定。通过采用这种新写法,你的代码将更加健壮,更易于维护,并且能通过严格的静态类型检查。
到此这篇关于SQLAlchemy 2.0 类型注解指南:`Mapped` 与 `mapped_column`的文章就介绍到这了,更多相关SQLAlchemy 2.0 类型注解内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!
您可能感兴趣的文章:
- python中的flask_sqlalchemy的使用及示例详解
- Python库SQLAlchemy的简介、用法和安装步骤详解
- Python ORM神器之SQLAlchemy基本使用完全指南
- python SQLAlchemy 数据库连接池的实现
- 深入浅出MappedByteBuffer(推荐)
- SQLAlchemy案例详解