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

Ric*_*ick 90 python sqlalchemy

我一直在试图弄清楚如何迭代SQLAlchemy模型中定义的列列表.我希望它能为一些模型编写一些序列化和复制方法.我不能只迭代obj.__dict__它,因为它包含很多特定于SA的项目.

任何人都知道如何从以下获取iddesc名称?

class JobStatus(Base):
    __tablename__ = 'jobstatus'

    id = Column(Integer, primary_key=True)
    desc = Column(Unicode(20))
Run Code Online (Sandbox Code Playgroud)

在这个小案例中,我可以轻松创建:

def logme(self):
    return {'id': self.id, 'desc': self.desc}
Run Code Online (Sandbox Code Playgroud)

但我更喜欢自动生成的东西dict(对于较大的对象).

谢谢你的帮助.

van*_*van 76

您可以使用以下功能:

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]))
Run Code Online (Sandbox Code Playgroud)

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

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

for c in JobStatus.__table__.columns:
    print c

for c in JobStatus.__table__.foreign_keys:
    print c
Run Code Online (Sandbox Code Playgroud)

请参阅如何从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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`__table __.columns`将为您提供SQL字段名称,而不是您在ORM定义中使用的属性名称(如果两者不同). (19认同)
  • 我可以建议将''_sa_'!= k [:4]`更改为`not k.startswith('_ sa _')`? (11认同)
  • 无需使用inspect循环:`inspect(JobStatus).columns.keys()` (10认同)

Ant*_*sma 61

您可以从映射器中获取已定义属性的列表.对于您的情况,您只对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)]
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这让我在Base上创建一个__todict__方法,然后我用它将一个实例"转储"到一个dict然后我可以通过pylon的jsonify装饰器响应.我尝试在我的原始问题中添加更多详细信息和代码示例,但这会导致stackoverflow在提交时出错. (4认同)
  • 顺便说一下,`class_mapper`需要从`sqlalchemy.orm`导入 (4认同)
  • 虽然这是一个合理的答案,但在版本0.8之后,建议使用`inspect()`,它返回与`class_mapper()`完全相同的映射器对象.http://docs.sqlalchemy.org/en/latest/core/inspection.html (3认同)

小智 28

我意识到这是一个老问题,但我只是遇到了同样的要求,并希望为未来的读者提供替代解决方案.

正如Josh所说,将返回完整的SQL字段名称JobStatus.__table__.columns,因此您将获得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)}
Run Code Online (Sandbox Code Playgroud)

从这里你可以简单地打电话JobStatus.__table__.columns._data.keys()给你一个漂亮,干净的清单:

['id', 'desc']
Run Code Online (Sandbox Code Playgroud)

  • 没有_data attr,只需..columns.keys()就可以了 (3认同)
  • 好的!有没有办法用这种方法来建立关系? (2认同)
  • 是的,应尽可能避免使用私有 _data 属性,@Humoyun 更正确。 (2认同)

小智 12

self.__table__.columns将"仅"为您提供该特定类中定义的列,即没有继承的列.如果你需要所有,请使用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)
Run Code Online (Sandbox Code Playgroud)


fla*_*ini 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
Run Code Online (Sandbox Code Playgroud)

然后在课堂上使用它

class MyClass(BaseMixin, Base):
    pass
Run Code Online (Sandbox Code Playgroud)

这样你就可以在一个实例上调用以下内容MyClass.

> myclass = MyClass()
> myclass.as_dict()
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.


我已经对此进行了更多的讨论,我实际上需要将我的实例渲染为HAL对象dict的形式,并将其链接到相关对象.所以我在这里添加了这个小魔法,它将爬过类的所有属性,与上面相同,不同之处在于我将更深入地抓取属性并自动生成这些属性.Relaionshiplinks

请注意,这仅适用于具有单个主键的关系

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
Run Code Online (Sandbox Code Playgroud)


jrc*_*jrc 6

假设您正在使用SQLAlchemy的声明性映射,则可以使用__mapper__attribute来获取类映射器。要获取所有映射的属性(包括关系):

obj.__mapper__.attrs.keys()
Run Code Online (Sandbox Code Playgroud)

如果需要严格的列名,请使用obj.__mapper__.column_attrs.keys()。有关其他视图,请参见文档。

https://docs.sqlalchemy.org/zh_CN/latest/orm/mapping_api.html#sqlalchemy.orm.mapper.Mapper.attrs