首页 文章

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

提问于
浏览
75

我've been trying to figure out how to iterate over the list of columns defined in a SQLAlchemy model. I want it for writing some serialization and copy methods to a couple of models. I can' t只是遍历 obj.__dict__ ,因为它包含很多特定于SA的项目 .

有人知道从下面获取 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 的东西(对于较大的对象) .

谢谢你的帮助 .

7 回答

  • 61

    您可以使用以下功能:

    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 继承,你有一个 __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 - 类似的问题 .

    Edit by 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
    
  • 24

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

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

    正如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']
    
  • 6

    self.__table__.columns 将"only"为您提供该特定类中定义的列,即没有继承的列 . 如果你需要全部,请使用 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)
    
  • 12

    为了在我的所有类上获得 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的形式's links to related objects. So I' ve在这里添加了这个小魔法,它将爬过类的所有属性,如上所述,不同之处在于我将更深入地抓取 Relaionship 属性并自动生成 links .

    Please note that this will only work for relationships have a single primary key

    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
    
  • -1

    假设你是're using 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

  • 0

    我知道这是一个老问题,但是怎么样:

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

相关问题