迭代sqlalchemy模型的定义列的方法?

我一直想弄清楚如何迭代在SqlAlchemy模型中定义的列的列表。 我想要写一些序列化和复制方法到一些模型。 我不能只遍历obj。 字典,因为它包含了大量的特定于SA的项目。

任何人都知道一个方法来获得id,并从以下desc名称?

class JobStatus(Base): __tablename__ = 'jobstatus' id = Column(Integer, primary_key=True) desc = Column(Unicode(20)) 

在这个小案例中,我可以轻松地创build一个:

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

但我更喜欢自动生成大对象的东西。

感谢您的帮助。

你可以使用下面的函数:

 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])) 

它会排除SA的魔法属性,但不会排除关系。 所以基本上它可能会加载依赖关系,父母,孩子等,这是绝对不可取的。

但是它实际上要容易得多,因为如果你从Baseinheritance,你有一个__table__属性,所以你可以这样做:

 for c in JobStatus.__table__.columns: print c for c in JobStatus.__table__.foreign_keys: print c 

请参阅如何从SQLAlchemy映射对象发现表属性 – 类似的问题。

Mike编辑:请参阅Mapper.c和Mapper.mapped_table等函数。 如果使用0.8或更高版本,请参见Mapper.attrs和相关函数。

Mapper.attrs示例:

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

您可以从映射器获取定义的属性的列表。 对于你的情况,你只对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)] 

我意识到这是一个古老的问题,但我刚刚遇到同样的要求,并希望为未来的读者提供一个替代解决scheme。

正如Josh指出的,完整的SQL字段名称将由JobStatus.__table__.columns ,而不是原始字段名称id ,您将获得jobstatus.id 。 没有它可能是有用的。

获得最初定义的字段名称列表的解决scheme是查看包含完整数据的列对象上的_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._data.keys() ,它给你一个不错的,干净的列表:

 ['id', 'desc'] 

self.__table__.columns将“只”给你在该特定类中定义的列,即没有inheritance的列。 如果您需要全部,请使用self.__mapper__.columns 。 在你的例子中,我可能会使用这样的东西:

 class JobStatus(Base): ... def __iter__(self): values = vars(self) for attr in self.__mapper__.columns.keys(): if attr in values: yield attr, values[attr] def logme(self): return dict(self) 

为了在我所有的类上得到一个as_dict方法,我使用了一个Mixin类,它使用了Ants Aasma描述的工艺。

 class BaseMixin(object): def as_dict(self): result = {} for prop in class_mapper(self.__class__).iterate_properties: if isinstance(prop, ColumnProperty): result[prop.key] = getattr(self, prop.key) return result 

然后在你的课堂上这样使用它

 class MyClass(BaseMixin, Base): pass 

这样你就可以在MyClass一个实例上调用下面的方法。

 > myclass = MyClass() > myclass.as_dict() 

希望这可以帮助。


我已经玩了一段时间了,我实际上需要把我的实例渲染为一个HAL对象的forms,并且链接到相关的对象。 所以我在这里添加了这个小小的魔法,它将爬过类的所有属性,不同之处在于我将深入到Relaionship属性中并自动生成这些属性的links

请注意,这只适用于关系有一个主键

 from functools import reduce def deepgetattr(obj, attr): """Recurses through an attribute chain to get the ultimate value.""" return reduce(getattr, attr.split('.'), obj) class BaseMixin(object): def as_dict(self): IgnoreInstrumented = ( InstrumentedList, InstrumentedDict, InstrumentedSet ) result = {} for prop in class_mapper(self.__class__).iterate_properties: if isinstance(getattr(self, prop.key), IgnoreInstrumented): # All reverse relations are assigned to each related instances # we don't need to link these, so we skip continue if isinstance(prop, ColumnProperty): # Add simple property to the dictionary with its value result[prop.key] = getattr(self, prop.key) if isinstance(prop, RelationshipProperty): # Construct links relaions if 'links' not in result: result['links'] = {} # Get value using nested class keys value = ( deepgetattr( self, prop.key + "." + prop.mapper.primary_key[0].key ) ) result['links'][prop.key] = {} result['links'][prop.key]['href'] = ( "/{}/{}".format(prop.key, value) ) return result 

我知道这是一个古老的问题,但是呢:

 class JobStatus(Base): ... def columns(self): return [col for col in dir(self) if isinstance(col, db.Column)] 

然后,获取列名: jobStatus.columns()

那会返回['id', 'desc']

然后,你可以循环,并与列和值做的东西:

 for col in jobStatus.colums(): doStuff(getattr(jobStatus, col))