如何为SQLAlchemy Mixins正确添加MyPy类型注解?
解决方案:用Protocol和交集类型实现类型标注
方案思路
通过Protocol定义"包含file字段"的类型约束,结合交集类型(Python 3.10+)或typing_extensions.Intersection(旧版本Python),让类型检查器识别同时满足"SQLAlchemy ORM模型"和"拥有file字段"的类。既无需创建额外ORM模型类,又能保证类型安全。
代码实现
1. 定义HasFile协议
创建仅用于类型标注的Protocol,描述具有file类属性的类型:
from typing import Protocol, ClassVar from sqlalchemy import Column, String class HasFile(Protocol): file: ClassVar[Column[String]]
这个Protocol仅用于类型检查,不会被SQLAlchemy注册为ORM模型。
2. 约束TypeVar并标注函数
使用交集类型约束TypeVar,确保传入的model既是BaseModel的子类,又实现HasFile协议:
from typing import List, Type, TypeVar from sqlalchemy.orm import Session # Python 3.10+ 支持原生交集类型 T = TypeVar("T", bound=BaseModel & HasFile) # Python 3.9及以下版本,需安装typing_extensions后使用 # from typing_extensions import Intersection # T = TypeVar("T", bound=Intersection[BaseModel, HasFile]) def file_query(db: Session, model: Type[T], file: str) -> List[T]: return db.query(model).filter(model.file == file).all()
效果说明
- 类型检查器(如mypy、pyright)会自动验证:传入的model必须是继承
BaseModel的ORM类,且包含file字段,非法传入会直接报错。 - 无需创建额外中间ORM类,避免被SQLAlchemy错误注册为不存在的数据库表。
- 函数返回值的类型会被正确推导为传入模型的实例列表,保持代码的类型一致性。
内容的提问来源于stack exchange,提问作者Albert Iribarne
相关产品推荐
相关产品推荐

