如何从SQLAlchemy模型实例获取ORM类以实现通用保存方法?
解决SQLAlchemy通用save_model方法的ORM类获取与属性过滤问题
核心问题分析
你遇到的报错并非因为model_type获取错误,而是两个关键问题:
- 直接传递ORM实例的
__dict__给contains方法,其中包含SQLAlchemy内部属性(如_sa_instance_state),这些属性不属于模型类的列,导致getattr(model_class, key)调用失败。 - 尝试用
Table或TextClause替代ORM类,这些对象本身不是SQLAlchemy ORM模型类,自然无法用于session.query()。
正确解决方案
1. 正确获取ORM类
对于SQLAlchemy ORM实例,直接用type(model)就能得到对应的ORM模型类,这是最直接且正确的方式。
2. 过滤实例属性,仅传递模型列
不能直接用**model.__dict__,因为ORM实例的__dict__包含内部属性。需要通过SQLAlchemy的inspect工具提取仅属于模型列的属性。
修正后的完整代码
from sqlalchemy import create_engine, inspect from sqlalchemy.orm import sessionmaker from typing import Type, Any # 假设Base是你的SQLAlchemy基类,Model是ORM模型的类型 class Database: """SQLAlchemy object for interacting with the database""" def __init__(self, db_url: str): self.engine = create_engine(db_url) Base.metadata.create_all(self.engine) Session = sessionmaker(bind=self.engine) self.session = Session() def save_model(self, model: Any) -> bool: """Saves given model to the database""" try: # 正确获取ORM模型类 model_type = type(model) # 提取仅包含模型列的属性 model_attrs = self._get_model_column_attrs(model) if self.contains(model_type, **model_attrs): return False self.session.add(model) self.session.commit() return True except Exception as e: self.session.rollback() raise Exception(f"Unable to save model: {str(e)}") return False def contains(self, model_class: Type[Any], **kwargs) -> bool: """Returns True if a model of the specified class with the given attributes exists in the database.""" query = self.session.query(model_class) for key, value in kwargs.items(): query = query.filter(getattr(model_class, key) == value) return query.first() is not None def _get_model_column_attrs(self, model: Any) -> dict[str, Any]: """提取ORM实例中仅属于模型列的属性""" insp = inspect(model) # 仅获取模型定义的列属性 return {col.key: getattr(model, col.key) for col in insp.mapper.column_attrs}
关键说明
inspect(model):SQLAlchemy提供的工具,用于获取ORM实例的元数据信息,包括映射的列属性。insp.mapper.column_attrs:直接获取模型类定义的所有列属性,避免包含内部属性。- 无需额外传入
model_class参数,完全通过实例自身推导ORM类。
内容的提问来源于stack exchange,提问作者bug_spray
相关产品推荐
相关产品推荐

