web-dev-qa-db-ja.com

sqlalchemy行オブジェクトをpython dictに変換します

列名と値のペアを反復処理する簡単な方法はありますか?

Sqlalchemyの私のバージョンは0.5.6です

Dict(row)を使用しようとしたサンプルコードを次に示しますが、例外、TypeErrorをスローします: 'User'オブジェクトは反復可能ではありません

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()):
    __table= '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
196
Anurag Uniyal

良い答えが得られなかったので、これを使用します:

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

    return d

編集:上記の機能が長すぎて一部の好みに適さない場合は、ここに1つのライナーがあります(python 2.7+)

row2dict = lambda r: {c.name: str(getattr(r, c.name)) for c in r.__table__.columns}
127
Anurag Uniyal

次のように、SQLAlchemyオブジェクトの内部__dict__にアクセスできます。

for u in session.query(User).all():
    print u.__dict__
199
hllau

SQLAlchemy v0.8以降では、 検査システム を使用します。

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 でも機能します。

65
RazerM
for row in resultproxy:
    row_as_dict = dict(row)
63
Alex Brasetvik

行には、辞書を与える_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'}
32
balki

@balkiが述べたように:

特定のフィールドが KeyedTuple として返されるため、特定のフィールドをクエリする場合は、_asdict()メソッドを使用できます。

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'}
17
Sam Bourne

古い質問ですが、これはGoogleの「sqlalchemy row to dict」の最初の結果なので、より良い答えに値します。

SqlAlchemyが返すRowProxyオブジェクトには、items()メソッドがあります。 http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

(キー、値)タプルのリストを返すだけです。したがって、以下を使用して行を辞書に変換できます。

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]
15
fgasparini
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)
12
Marco Mariani

@balkiの答えに続いて、SQLAlchemy 0.8から、KeyedTupleオブジェクトで使用可能な_asdict()を使用できます。これにより、元の質問に対する非常に簡単な答えが得られます。ちょうど、この例の最後の2行(forループ)を変更してください。

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

これは、上記のコードでは、.all()がKeyedTupleのリストを返すため、uはタイプクラス KeyedTuple のオブジェクトであるため機能します。したがって、メソッド _ asdict() があり、これは辞書としてうまくuを返します。

WRTの@STBによる答え:AFAIK、.all()が返すanithongはKeypedTupleのリストです。したがって、クエリオブジェクトに適用された.all()の結果を処理している限り、列を指定するかどうかにかかわらず、上記は機能します。

10
jgbarah

以下の関数が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またはその他の属性SQLalchemyまたはオブジェクトに追加する属性は含まれません。 参照

編集:これは継承された列でも機能することを忘れてください。

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_

ここでは、_によって属性にアクセスするか、単に表示したくないため、列を開始するhybrid_propertyでマークして非表示にすることを示していると仮定します。 参照

Tipall_orm_descriptorshybrid_method および AssociationProxy も返します。

他の回答へのコメント

__dict__属性に基づくすべての回答( 12 など)は、オブジェクトのすべての属性を単に返します。これは、必要な属性よりもはるかに多くなる可能性があります。悲しいことに、これには_sa_instance_stateまたはこのオブジェクトで定義する他の属性が含まれます。

dict()関数に基づくすべての回答( 12 など)は、session.execute()によって返されるSQLalchemy行オブジェクトでのみ機能します質問のclass Userのように、操作するように定義したクラスではありません。

row.__table__.columnsに基づく 解答 は間違いなくnot動作します。 row.__table__.columnsには、SQLデータベースの列名が含まれます。これらは、pythonオブジェクトの属性名とのみ同じにすることができます。そうでない場合は、AttributeErrorを取得します。 class_mapper(obj.__class__).mapped_table.cに基づく回答( 12 など)の場合も同じです。

9
F.Raab

繰り返し処理する式は、行ではなくモデルオブジェクトのリストに評価されます。したがって、以下はそれらの正しい使用法です。

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()に役立ちます。

8
Denis Otkidach

Alex Brasetvik's Answer を参照してください。1行のコードを使用して問題を解決できます。

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

Alex Brasetvikの回答のコメントセクションで、SQLAlchemyの作成者であるzzzeekは、これが問題の「正しい方法」であると述べました。

7
NorWay

SQLAlchemyの行を辞書に変換する方法を探していたため、この投稿を見つけました。私はSqlSoupを使用していますが、答えは自分で作成したので、もしそれが誰かに役立つなら、私の2セントです:

a = db.execute('select * from acquisizioni_motes')
b = a.fetchall()
c = b[0]

# and now, finally...
dict(Zip(c.keys(), c.values()))
7
Mychot sad

この方法で試してみることができます。

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

クエリオブジェクトの組み込みオブジェクトを使用して、クエリオブジェクトの辞書オブジェクトを返します。

参照: https://docs.sqlalchemy.org/en/latest/orm/query.html

4
Enmanuel Medina

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)
4
Chirag Vora

二通り:

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())
3
FrostSigh

ドキュメントは非常にシンプルなソリューションを提供します: ResultRow._asdict()

def to_array(rows):
    return [r._asdict() for r in rows]

def query():
    data = session.query(Table).all()
    return to_array(data)
3
J.B.

Elixirの仕組みは次のとおりです。このソリューションの価値は、リレーションシップの辞書表現を再帰的に含めることができることです。

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
2
argentpepper

このコードを使用すると、クエリに「フィルター」または「結合」を追加することもできます!

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]
2
Yakir Tsuberi

マルコ・マリアーニの答えにはバリエーションがあり、デコレーターとして表現されています。主な違いは、エンティティのlistsを処理するだけでなく、他の種類の戻り値を安全に無視することです(モックを使用してテストを記述するときに非常に便利です)。

@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
1
Chris R
class User(object):
    def to_dict(self):
        return dict([(k, getattr(self, k)) for k in self.__dict__.keys() if not k.startswith("_")])

うまくいくはずです。

1
Singletoned

この: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'}
0
Eds_k

モデルテーブルの列が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}

この方法を使用すると、modify_timeとcreate_timeの両方がNoneになります

{'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の列ストアと等しくないため

0
张小诚
def to_dict(row):
    return {column.name: getattr(row, row.__mapper__.get_property_by_column(column).key) for column in row.__table__.columns}


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

この機能が役立つ場合があります。属性名が列名と異なる場合、問題を解決するためのより良い解決策を見つけることができません。

@Anurag Uniyalの答えを完成させるために、関係を再帰的にたどるメソッドを次に示します。

from sqlalchemy.inspection import inspect

def to_dict(obj, with_relationships=True):
    d = {}
    for column in obj.__table__.columns:
        if with_relationships and len(column.foreign_keys) > 0:
             # Skip foreign keys
            continue
        d[column.name] = getattr(obj, column.name)

    if with_relationships:
        for relationship in inspect(type(obj)).relationships:
            val = getattr(obj, relationship.key)
            d[relationship.key] = to_dict(val) if val else None
    return d

class User(Base):
    __table= 'users'
    id = Column(Integer, primary_key=True)
    first_name = Column(TEXT)
    address_id = Column(Integer, ForeignKey('addresses.id')
    address = relationship('Address')

class Address(Base):
    __table= 'addresses'
    id = Column(Integer, primary_key=True)
    city = Column(TEXT)


user = User(first_name='Nathan', address=Address(city='Lyon'))
# Add and commit user to session to create ids

to_dict(user)
# {'id': 1, 'first_name': 'Nathan', 'address': {'city': 'Lyon'}}
to_dict(user, with_relationship=False)
# {'id': 1, 'first_name': 'Nathan', 'address_id': 1}
0
nbarraille

あなたはプロジェクトのどこでもそれを必要とします、私は@anuragがそれがうまく働くと答えました。この時点まで私はそれを使用していましたが、それはあなたのすべてのコードを台無しにし、エンティティの変更でも動作しません。

むしろこれを試して、SQLAlchemyで基本クエリクラスを継承してください

from flask_sqlalchemy import SQLAlchemy, BaseQuery


class Query(BaseQuery):
    def as_dict(self):
        context = self._compile_context()
        context.statement.use_labels = False
        columns = [column.name for column in context.statement.columns]

        return list(map(lambda row: dict(Zip(columns, row)), self.all()))


db = SQLAlchemy(query_class=Query)

その後、オブジェクト「as_dict」メソッドを定義する場所はどこにでもあります。

0
Yash Pokar

みんなと私のために、私はそれをどのように使用するかです:

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]
0
bigdatamann

私は新しく造られたPythonプログラマであり、JoinedテーブルでJSONを取得する際に問題に遭遇しました。ここでの回答からの情報を使用して、テーブル名が含まれるJSONに適切な結果を返す関数を作成し、エイリアスを作成したりフィールドを衝突させたりしないようにしました。

セッションクエリの結果を渡すだけです。

test = Session()。query(VMInfo、Customer).join(Customer).order_by(VMInfo.vm_name).limit(50).offset(10)

json = sqlAl2json(test)

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