迭代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的魔法属性,但不会排除关系。 所以基本上它可能会加载依赖关系,父母,孩子等,这是绝对不可取的。
但是它实际上要容易得多,因为如果你从Base
inheritance,你有一个__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))