代码之家  ›  专栏  ›  技术社区  ›  Anurag Uniyal

将sqlalchemy行对象转换为python dict

  •  182
  • Anurag Uniyal  · 技术社区  · 16 年前

    有没有一种简单的方法来遍历列名和值对?

    我的sqlalchemy版本是0.5.6

    下面是我尝试使用dict(row)的示例代码,但它抛出异常,typeerror:“user”对象不可iterable

    import sqlalchemy
    from sqlalchemy import *
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import sessionmaker
    
    print "sqlalchemy version:",sqlalchemy.__version__ 
    
    engine = create_engine('sqlite:///:memory:', echo=False)
    metadata = MetaData()
    users_table = Table('users', metadata,
         Column('id', Integer, primary_key=True),
         Column('name', String),
    )
    metadata.create_all(engine) 
    
    class User(declarative_base()):
        __tablename__ = 'users'
    
        id = Column(Integer, primary_key=True)
        name = Column(String)
    
        def __init__(self, name):
            self.name = name
    
    Session = sessionmaker(bind=engine)
    session = Session()
    
    user1 = User("anurag")
    session.add(user1)
    session.commit()
    
    # uncommenting next line throws exception 'TypeError: 'User' object is not iterable'
    #print dict(user1)
    # this one also throws 'TypeError: 'User' object is not iterable'
    for u in session.query(User).all():
        print dict(u)
    

    在系统输出上运行此代码:

    sqlalchemy version: 0.5.6
    Traceback (most recent call last):
      File "untitled-1.py", line 37, in <module>
        print dict(u)
    TypeError: 'User' object is not iterable
    
    30 回复  |  直到 7 年前
        1
  •  171
  •   Mark Amery Harley Holcombe    7 年前

    您可以访问内部 __dict__ 一个sqlalchemy对象,如下所示:

    for u in session.query(User).all():
        print u.__dict__
    
        2
  •  121
  •   Community Mohan Dere    12 年前

    我找不到一个好答案,所以我用这个:

    def row2dict(row):
        d = {}
        for column in row.__table__.columns:
            d[column.name] = str(getattr(row, column.name))
    
        return d
    

    编辑:如果上面的函数太长,不适合某些口味,这里有一个一行程序(Python2.7+)

    row2dict = lambda r: {c.name: str(getattr(r, c.name)) for c in r.__table__.columns}
    
        3
  •  64
  •   Mark Amery Harley Holcombe    7 年前

    在sqlalchemy v0.8及更新版本中,使用 inspection system .

    from sqlalchemy import inspect
    
    def object_as_dict(obj):
        return {c.key: getattr(obj, c.key)
                for c in inspect(obj).mapper.column_attrs}
    
    user = session.query(User).first()
    
    d = object_as_dict(user)
    

    注意到 .key 是属性名,可以不同于列名,例如在以下情况下:

    class_ = Column('class', Text)
    

    这种方法也适用于 column_property .

        4
  •  54
  •   Alex Brasetvik    16 年前
    for row in resultproxy:
        row_as_dict = dict(row)
    
        5
  •  30
  •   balki    12 年前

    行有 _asdict() 发出指令的函数

    In [8]: r1 = db.session.query(Topic.name).first()
    
    In [9]: r1
    Out[9]: (u'blah')
    
    In [10]: r1.name
    Out[10]: u'blah'
    
    In [11]: r1._asdict()
    Out[11]: {'name': u'blah'}
    
        6
  •  15
  •   Sam Bourne    11 年前

    正如@balki提到的:

    这个 _asdict() 如果查询特定字段,则可以使用方法,因为它作为 KeyedTuple .

    In [1]: foo = db.session.query(Topic.name).first()
    In [2]: foo._asdict()
    Out[2]: {'name': u'blah'}
    

    但是,如果不指定列,则可以使用其他建议的方法之一,例如@charlax提供的方法。请注意,此方法仅对2.7+有效。

    In [1]: foo = db.session.query(Topic).first()
    In [2]: {x.name: getattr(foo, x.name) for x in foo.__table__.columns}
    Out[2]: {'name': u'blah'}
    
        7
  •  14
  •   fgasparini    9 年前

    旧问题,但由于这是“sqlalchemy row to dict”在谷歌的第一个结果,它应该得到一个更好的答案。

    sqlalchemy返回的rowproxy对象具有items()方法: http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

    它只返回(键,值)元组的列表。因此,可以使用以下命令将行转换为dict:

    在python<=2.6中:

    rows = conn.execute(query)
    list_of_dicts = [dict((key, value) for key, value in row.items()) for row in rows]
    

    在python>=2.7中:

    rows = conn.execute(query)
    list_of_dicts = [{key: value for (key, value) in row.items()} for row in rows]
    
        8
  •  12
  •   Marco Mariani    16 年前
    from sqlalchemy.orm import class_mapper
    
    def asdict(obj):
        return dict((col.name, getattr(obj, col.name))
                    for col in class_mapper(obj.__class__).mapped_table.c)
    
        9
  •  9
  •   jgbarah    11 年前

    按照巴尔基的回答, 自SQLAlchemy 0.8以来 您可以使用asdict(),可用于keyeduple对象。这使得对原始问题的回答相当直接。只是,在您的示例中更改此示例的最后两行(for循环):

    for u in session.query(User).all():
       print u._asdict()
    

    这是因为在上面的代码中,u是类类型的对象 KeyedTuple ,因为.all()返回keyeduple的列表。因此它有方法 _asdict() ,它很好地将u作为字典返回。

    答案由@stb:afaik给出,答案是.all()返回的是一个keypeduple列表。因此,只要处理应用于查询对象的.all()的结果,无论是否指定了列,上述方法都有效。

        10
  •  8
  •   Denis Otkidach    16 年前

    正在迭代的表达式计算为模型列表 物体 不是行。所以下面是正确的用法:

    for u in session.query(User).all():
        print u.id, u.name
    

    你真的需要把它们转换成口述吗?当然,有很多方法,但是您不需要sqlalchemy的orm部分:

    result = session.execute(User.__table__.select())
    for row in result:
        print dict(row)
    

    更新 :看一看 sqlalchemy.orm.attributes 模块。它有一组函数来处理对象状态,这对您可能很有用,特别是 instance_dict() .

        11
  •  7
  •   Mychot sad    14 年前

    我找到这篇文章是因为我在寻找一种方法来将sqlalchemy行转换成dict。但答案是我自己建立的,所以,如果能帮上忙的话,这是我的两分钱:

    a = db.execute('select * from acquisizioni_motes')
    b = a.fetchall()
    c = b[0]
    
    # and now, finally...
    dict(zip(c.keys(), c.values()))
    
        12
  •  7
  •   Community Mohan Dere    9 年前

    假设以下函数将添加到 class User 下面将返回所有列的所有键值对:

    def columns_to_dict(self):
        dict_ = {}
        for key in self.__mapper__.c.keys():
            dict_[key] = getattr(self, key)
        return dict_
    

    与其他答案不同,只返回对象的属性 Column 对象的类级别的属性。因此没有 _sa_instance_state 或任何其他属性 圣卢西亚 或者添加到对象中。 Reference

    编辑:忘了说,这也适用于继承的列。

    hybrid_propery 延伸

    如果您还想包括 hybrid_property 属性以下项将起作用:

    from sqlalchemy import inspect
    from sqlalchemy.ext.hybrid import hybrid_property
    
    def publics_to_dict(self) -> {}:
        dict_ = {}
        for key in self.__mapper__.c.keys():
            if not key.startswith('_'):
                dict_[key] = getattr(self, key)
    
        for key, prop in inspect(self.__class__).all_orm_descriptors.items():
            if isinstance(prop, hybrid_property):
                dict_[key] = getattr(self, key)
        return dict_
    

    我假设你在这里用一个开头来标记列 _ 以指示您要隐藏它们,因为您可以通过 混合财产 或者你只是不想让他们知道。 Reference

    蒂普 all_orm_descriptors 也回报 hybrid_method AssociationProxy 如果你还想包括他们。

    对其他答案的评论

    每个答案(比如 1 , 2 )基于 __dict__ 属性只返回对象的所有属性。这可能比你想要的更多。我很难过这包括 _实例状态 或在此对象上定义的任何其他属性。

    每个答案(比如 1 , 2 )基于 dict() 函数只作用于 圣卢西亚 返回的行对象 session.execute() 不在您定义要使用的类上,如 类用户 从这个问题。

    这个 solving answer 基于 row.__table__.columns 一定会的 工作。 行。列 包含SQL数据库的列名。这些 只能 等于python对象的属性名。如果你没有得到 AttributeError . 答案(比如 1 , 2 )基于 class_mapper(obj.__class__).mapped_table.c 是一样的。

        13
  •  6
  •   NorWay    9 年前

    参照 Alex Brasetvik's Answer ,您可以使用一行代码来解决问题

    row_as_dict = [dict(row) for row in resultproxy]
    

    在alex brasetvik的回答的注释部分,sqlalchemy的创建者zzzeek声明这是解决问题的“正确方法”。

        14
  •  3
  •   Chirag Vora    8 年前

    您可以像这样将sqlalchemy对象转换为字典,并将其作为json/dictionary返回。

    帮助函数:

    import json
    from collections import OrderedDict
    
    
    def asdict(self):
        result = OrderedDict()
        for key in self.__mapper__.c.keys():
            if getattr(self, key) is not None:
                result[key] = str(getattr(self, key))
            else:
                result[key] = getattr(self, key)
        return result
    
    
    def to_array(all_vendors):
        v = [ ven.asdict() for ven in all_vendors ]
        return json.dumps(v) 
    

    驱动功能:

    def all_products():
        all_products = Products.query.all()
        return to_array(all_products)
    
        15
  •  3
  •   yellow-saint    7 年前

    文档提供了一个非常简单的解决方案: ResultRow._asdict()

    def to_array(rows):
        return [r._asdict() for r in rows]
    
    def query():
        data = session.query(Table).all()
        return to_array(data)
    
        16
  •  2
  •   dequis argentpepper    10 年前

    这是长生不老药的作用。这个解决方案的价值在于它允许递归地包含关系的字典表示。

    def to_dict(self, deep={}, exclude=[]):
        """Generate a JSON-style nested dict/list structure from an object."""
        col_prop_names = [p.key for p in self.mapper.iterate_properties \
                                      if isinstance(p, ColumnProperty)]
        data = dict([(name, getattr(self, name))
                     for name in col_prop_names if name not in exclude])
        for rname, rdeep in deep.iteritems():
            dbdata = getattr(self, rname)
            #FIXME: use attribute names (ie coltoprop) instead of column names
            fks = self.mapper.get_property(rname).remote_side
            exclude = [c.name for c in fks]
            if dbdata is None:
                data[rname] = None
            elif isinstance(dbdata, list):
                data[rname] = [o.to_dict(rdeep, exclude) for o in dbdata]
            else:
                data[rname] = dbdata.to_dict(rdeep, exclude)
        return data
    
        17
  •  2
  •   Yakir Tsuberi    8 年前

    使用此代码,您还可以添加到查询“filter”或“join”和此工作!

    query = session.query(User)
    def query_to_dict(query):
            def _create_dict(r):
                return {c.get('name'): getattr(r, c.get('name')) for c in query.column_descriptions}
    
        return [_create_dict(r) for r in query]
    
        18
  •  2
  •   Enmanuel Medina    7 年前

    你可以试着这样做。

    for u in session.query(User).all():
        print(u._asdict())
    

    它在查询对象中使用内置方法,该方法返回查询对象的dictional对象。

    参考文献: https://docs.sqlalchemy.org/en/latest/orm/query.html

        19
  •  1
  •   Singletoned    16 年前
    class User(object):
        def to_dict(self):
            return dict([(k, getattr(self, k)) for k in self.__dict__.keys() if not k.startswith("_")])
    

    这应该管用。

        20
  •  1
  •   Chris R    16 年前

    我对马可·马里亚尼的回答有不同的看法,他是一个装潢师。主要的区别在于 列表 以及安全地忽略某些其他类型的返回值(这在使用mock编写测试时非常有用):

    @decorator
    def to_dict(f, *args, **kwargs):
      result = f(*args, **kwargs)
      if is_iterable(result) and not is_dict(result):
        return map(asdict, result)
    
      return asdict(result)
    
    def asdict(obj):
      return dict((col.name, getattr(obj, col.name))
                  for col in class_mapper(obj.__class__).mapped_table.c)
    
    def is_dict(obj):
      return isinstance(obj, dict)
    
    def is_iterable(obj):
      return True if getattr(obj, '__iter__', False) else False
    
        21
  •  1
  •   FrostSigh    8 年前

    两种方式:

    1。

    for row in session.execute(session.query(User).statement):
        print(dict(row))
    

    2。

    selected_columns = User.__table__.columns
    rows = session.query(User).with_entities(*selected_columns).all()
    for row in rows :
        print(row._asdict())
    
        22
  •  0
  •   tknightowl    10 年前

    我是一个新开发的python程序员,在使用连接表获取json时遇到了问题。使用这里的答案中的信息,我构建了一个函数,将合理的结果返回到json,在json中包含表名,避免了必须使用别名或字段冲突。

    只需传递会话查询的结果:

    test=session().query(vminfo,customer).join(customer).order_by(vminfo.vm_name).limit(50).offset(10)

    json=sqlal2json(测试)

    def sqlAl2json(self, result):
        arr = []
        for rs in result.all():
            proc = []
            try:
                iterator = iter(rs)
            except TypeError:
                proc.append(rs)
            else:
                for t in rs:
                    proc.append(t)
    
            dict = {}
            for p in proc:
                tname = type(p).__name__
                for d in dir(p):
                    if d.startswith('_') | d.startswith('metadata'):
                        pass
                    else:
                        key = '%s_%s' %(tname, d)
                        dict[key] = getattr(p, d)
            arr.append(dict)
        return json.dumps(arr)
    
        23
  •  0
  •   bzd111    8 年前

    如果models表列不是equie mysql列。

    例如:

    class People:
        id: int = Column(name='id', type_=Integer, primary_key=True)
        createdTime: datetime = Column(name='create_time', type_=TIMESTAMP,
                                   nullable=False,
                                   server_default=text("CURRENT_TIMESTAMP"),
                                   default=func.now())
        modifiedTime: datetime = Column(name='modify_time', type_=TIMESTAMP,
                                    server_default=text("CURRENT_TIMESTAMP"),
                                    default=func.now())
    

    需要使用:

     from sqlalchemy.orm import class_mapper 
     def asDict(self):
            return {x.key: getattr(self, x.key, None) for x in
                class_mapper(Application).iterate_properties}
    

    如果你用这种方法,你可以得到修改时间和创建时间都不是

    {'id': 1, 'create_time': None, 'modify_time': None}
    
    
        def to_dict(self):
            return {c.name: getattr(self, c.name, None)
             for c in self.__table__.columns}
    

    因为在mysql中类属性名不等于列存储

        24
  •  0
  •   Eds_k    7 年前

    返回this:class的内容: .KeyedTuple 作为字典

    In [46]: result = aggregate_events[0]
    
    In [47]: type(result)
    Out[47]: sqlalchemy.util._collections.result
    
    In [48]: def to_dict(query_result=None):
        ...:     cover_dict = {key: getattr(query_result, key) for key in query_result.keys()}
        ...:     return cover_dict
        ...: 
        ...:     
    
    In [49]: to_dict(result)
    Out[49]: 
    {'calculate_avg': None,
     'calculate_max': None,
     'calculate_min': None,
     'calculate_sum': None,
     'dataPointIntID': 6,
     'data_avg': 10.0,
     'data_max': 10.0,
     'data_min': 10.0,
     'data_sum': 60.0,
     'deviceID': u'asas',
     'productID': u'U7qUDa',
     'tenantID': u'CvdQcYzUM'}
    
        25
  •  0
  •   human    7 年前

    为了大家和我自己,下面是我的使用方法:

    def run_sql(conn_String):
      output_connection = engine.create_engine(conn_string, poolclass=NullPool).connect()
      rows = output_connection.execute('select * from db1.t1').fetchall()  
      return [dict(row) for row in rows]
    
        26
  •  -1
  •   Community Mohan Dere    9 年前

    在大多数情况下,列名适合它们。但也许你写的代码如下:

    class UserModel(BaseModel):
        user_id = Column("user_id", INT, primary_key=True)
        email = Column("user_email", STRING)
    

    列名“user_email”字段名为“email”时,列名不能像以前那样正常工作。

    sqlalchemy_base_model.py

    also i write the answer here

        27
  •  -1
  •   magne4000    10 年前

    一个同样适用于继承类的解决方案:

    from itertools import chain
    from sqlalchemy.ext.declarative import declarative_base
    Base = declarative_base()
    
    
    class Mixin(object):
        def as_dict(self):
            tables = [base.__table__ for base in self.__class__.__bases__ if base not in [Base, Mixin]]
            tables.append(self.__table__)
            return {c.name: getattr(self, c.name) for c in chain.from_iterable([x.columns for x in tables])}
    
        28
  •  -2
  •   user2444711    13 年前

    这是一个非常简单的方法

    row2dict = lambda r: dict(r.items())
    
        29
  •  -2
  •   Ralph Case    10 年前

    我对此没有太多经验,但以下几点似乎对我正在做的工作有用:

    dict(row)
    

    这似乎太简单了(与这里的其他答案相比)。我错过了什么?

        30
  •  -3
  •   Sawyer Brooks    10 年前

    我利用(太多?)词典:

    def serialize(_query):
    #d = dictionary written to per row
    #D = dictionary d is written to each time, then reset
    #Master = dictionary of dictionaries; the id Key (int, unique from database) from D is used as the Key for the dictionary D entry in Master
    Master = {}
    D = {}
    x = 0
    for u in _query:
        d = u.__dict__
        D = {}
        for n in d.keys():
            if n != '_sa_instance_state':
                D[n] = d[n]
        x = d['id']
        Master[x] = D
    return Master
    

    使用flask(包括jsonify)和flask_sqlalchemy运行以将输出打印为json。

    使用jsonify(serialize())调用函数。

    适用于迄今为止我尝试过的所有sqlalchemy查询(运行sqlite3)