如何遍历SQLAlchemy模型定义的列?

127 投票
11 回答
91527 浏览
提问于 2025-04-15 20:59

我一直在想怎么遍历一个SQLAlchemy模型中定义的列列表。我想这样做是为了给几个模型写一些序列化和复制的方法。因为直接遍历obj.__dict__不行,因为里面有很多特定于SQLAlchemy的东西。

有没有人知道怎么只获取下面这些的iddesc名字呢?

class JobStatus(Base):
    __tablename__ = 'jobstatus'

    id = Column(Integer, primary_key=True)
    desc = Column(Unicode(20))

在这个小例子中,我可以很容易地创建一个:

def logme(self):
    return {'id': self.id, 'desc': self.desc}

但我更希望有一种方法可以自动生成dict(对于更大的对象)。

11 个回答

37

我知道这个问题已经有点旧了,但我最近遇到了同样的需求,想给未来的读者提供一个替代的解决方案。

正如Josh提到的,通过JobStatus.__table__.columns可以得到完整的SQL字段名,所以你得到的不是原来的字段名id,而是jobstatus.id。这并没有那么实用。

要获取字段名的原始定义,可以查看列对象上的_data属性,它包含了完整的数据。如果我们查看JobStatus.__table__.columns._data,它的样子是这样的:

{'desc': Column('desc', Unicode(length=20), table=<jobstatus>),
 'id': Column('id', Integer(), table=<jobstatus>, primary_key=True, nullable=False)}

从这里你可以简单地调用JobStatus.__table__.columns.keys(),这样就能得到一个干净整洁的字段名列表:

['id', 'desc']
66

你可以从映射器那里获取定义好的属性列表。在你的情况下,你只需要关注 ColumnProperty 对象。

from sqlalchemy.orm import class_mapper
import sqlalchemy

def attribute_names(cls):
    return [prop.key for prop in class_mapper(cls).iterate_properties
        if isinstance(prop, sqlalchemy.orm.ColumnProperty)]
114

你可以使用下面这个函数:

def __unicode__(self):
    return "[%s(%s)]" % (self.__class__.__name__, ', '.join('%s=%s' % (k, self.__dict__[k]) for k in sorted(self.__dict__) if '_sa_' != k[:4]))

这个函数会排除掉一些特别的“魔法”属性,但不会排除关系。所以基本上,它可能会加载一些依赖、父级、子级等等,这样的结果其实并不理想。

不过其实事情要简单得多,因为如果你从 Base 继承,你就会有一个 __table__ 属性,这样你就可以做:

for c in JobStatus.__table__.columns:
    print c

for c in JobStatus.__table__.foreign_keys:
    print c

可以参考这个链接:如何从SQLAlchemy映射对象中发现表属性 - 这是一个类似的问题。

编辑者Mike:请查看一些函数,比如 Mapper.cMapper.mapped_table。如果你使用的是0.8版本及以上,还可以查看 Mapper.attrs 和相关函数。

关于 Mapper.attrs 的示例:

from sqlalchemy import inspect
mapper = inspect(JobStatus)
for column in mapper.attrs:
    print column.key

撰写回答