SQLAlchemy 对声明类的内省

7 投票
3 回答
2509 浏览
提问于 2025-04-16 02:08

我正在写一个小工具,用来从MySQL数据库导出数据,并进行一些简单的数据转换——主要是更改字段名称。我的脚本现在运行得很好,但我需要在类声明中描述我的模型两次——一次是在类的定义里,另一次是作为一个字段名称的列表来遍历。

我想弄清楚如何使用反射来识别行对象上的属性,这些属性是列的访问器。下面的代码几乎完美地工作:

for attr, value in self.__class__.__dict__.iteritems():
    if isinstance(value, sqlalchemy.orm.attributes.InstrumentedAttribute):
        self.__class__._columns.append(attr)

但我的多对多关系的访问器也是sqlalchemy.orm.attributes.InstrumentedAttribute的实例,我需要跳过这些。在检查类字典时,有没有办法区分这两者呢?

我找到的大部分关于sqlalchemy反射的文档都涉及到查看metadata.table,但由于我在重命名列,这些数据并不是简单可映射的。

3 个回答

1

一个 InstrumentedAttribute 实例有一个叫做 impl 的属性,实际上这个属性可以是 ScalarAttributeImplScalarObjectAttributeImpl 或者 CollectionAttributeImpl 其中之一。

我不太确定这个判断有多脆弱,但我只是检查它是哪一种,以确定这个实例最终会返回一个列表还是一个单独的对象。

7

每个被映射的实体都有一个叫做 columns 的属性,这个属性里面包含了所有的列定义。比如说,如果你有一个声明式的类 User,你可以通过 User.__mapper__ 来访问这个映射器,然后用下面的方式来获取列的信息:

list(User.__mapper__.columns)

每一列都有几个属性,比如 name(这个名字可能和映射的属性 key 不一样)、nullableunique 等等……

1

我还是想看到这个问题的答案,不过我通过改变关系访问器的名字来解决了这个问题(比如用'_otherentity'代替'otherentity'),然后根据名字进行筛选。这样做对我来说效果很好。

撰写回答