我一直在试图弄清楚如何迭代SQLAlchemy模型中定义的列列表。我希望它能为一些模型编写一些序列化和复制方法。我不能只遍历obj.__dict__
,因为它包含很多特定于SA的项目。
任何人都知道从以下方式获取id
和desc
名称的方法吗?
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
的内容(对于较大的对象)。
感谢您的帮助。
答案 0 :(得分:65)
您可以使用以下功能:
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 magic 属性,但不排除关系。所以基本上它可能会加载依赖项,父项,子项等,这绝对不可取。
但它实际上要容易得多,因为如果您从Base
继承,则会有__table__
属性,以便您可以这样做:
for c in JobStatus.__table__.columns:
print c
for c in JobStatus.__table__.foreign_keys:
print c
请参阅How to discover table properties from SQLAlchemy mapped object - 类似问题。
由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
答案 1 :(得分:59)
您可以从映射器中获取已定义属性的列表。对于您的情况,您只对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)]
答案 2 :(得分:27)
我意识到这是一个老问题,但我只是遇到了同样的要求,并希望为未来的读者提供替代解决方案。
正如Josh指出的那样,JobStatus.__table__.columns
将返回完整的SQL字段名称,因此您将获得 jobstatus.id 而不是原始字段名 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._data.keys()
,它会给你一个漂亮,干净的清单:
['id', 'desc']
答案 3 :(得分:12)
self.__table__.columns
只会&#34;&#34;为您提供该特定类中定义的列,即没有继承的列。如果您需要全部,请使用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)
答案 4 :(得分:7)
要在我的所有课程中获得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()
希望这有帮助。
我已经进一步玩了这个,我实际上需要将我的实例渲染为dict
,形式为HAL object,并带有相关对象的链接。所以我在这里添加了这个小魔法,它会抓取与上面相同的类的所有属性,不同之处在于我将更深入地抓取Relaionship
属性并自动生成links
请注意,这仅适用于具有单个主键的关系
from sqlalchemy.orm import class_mapper, ColumnProperty
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
答案 5 :(得分:3)
假设您正在使用SQLAlchemy的声明性映射,则可以使用__mapper__
属性来获取类映射器。要获取所有映射的属性(包括关系):
obj.__mapper__.attrs.keys()
如果要严格使用列名,请使用obj.__mapper__.column_attrs.keys()
。有关其他视图,请参见文档。
https://docs.sqlalchemy.org/en/latest/orm/mapping_api.html#sqlalchemy.orm.mapper.Mapper.attrs
答案 6 :(得分:0)
self.__dict__
返回一个字典,其中的键是属性名称,值是对象的值。
/!\有一个补充属性:'_sa_instance_state' 但您可以处理:)
答案 7 :(得分:0)
我想动态获取模型的特定实例的数据。我使用了这段代码。
def to_json(instance):
# get columns data
data = {}
columns = list(instance.__table__.columns)
for column in columns:
data[column.name] = instance.__dict__[column.name]
return data
答案 8 :(得分:-1)
我知道这是一个老问题,但是:
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))