sqlalchemy行オブジェクトをPython dictに変換する


240

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

私の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()):
    __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

3
質問のタイトルが質問自体と一致しません。ドキュメントに よると、複数のORMエンティティや列式を含むQueryによって返される結果行は、このクラスを使用して行を返します。どここのクラスは、あるsqlalchemy.util.KeyedTupleある行オブジェクト質問のタイトルから。ただし、質問のクエリはモデル(マップ済み)クラスを使用しているため、行オブジェクトのタイプはではなくモデルクラスですsqlalchemy.util.KeyedTuple
Piotr Dobrogost

2
@PiotrDobrogost質問は2009年のもので、sqlalchemyバージョン0.5.6に言及しています
Anurag Uniyal

回答:


232

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

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

24
このスレッドでの最良の答えは、なぜ誰もがはるかに複雑なソリューションを提案しているのかわからないことです。
Dave Rawks

92
これにより、少なくともバージョン0.7.9では、追加の「_sa_instance_state」フィールドが提供されます。
elbear 2012年

21
これは良いだろう:dictret = dict(row.__dict__); dictret.pop('_sa_instance_state', None)
ライフィング

6
人々が指摘しているよう__dict__に、_sa_instance_state削除する必要があるエントリが含まれているため、これは理想的ではないようです。将来のバージョンにアップグレードし、他の属性が追加された場合は、戻って手動でそれらを処理する必要があります。列データのみが必要な場合(たとえば、クエリからインスタンスのリストを取得し、それらをpandasデータフレームにドロップする場合)、{col.name: getattr(self, col.name) for col in self.__table__.columns}Anurag Uniyalによる回答(コメントからその回答への重要な修正を含む)の方が簡潔かつエラーのようです-証明。
kilgoretrout 2016

14
この答えは間違っています。質問にdict(u)は、それがスローされることもあり、正しく記述されていTypeErrorます。
RazerM

146

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

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

    return d

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

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

17
より簡潔に、return dict((col, getattr(row, col)) for col in row.__table__.columns.keys())
argentpepper 2012年

4
@argentpepperええ、あなたはrow2dict = lambda row: dict((col, getattr(row, col)) for col in row.__table__.columns.keys())それを本当の1つのライナーにするために行うことさえできますが、私は私のコードが読みやすく、横に短い、縦に長いことを好みます
Anurag Uniyal

14
列が同じ名前の属性に割り当てられていない場合はどうなりますか?IE 、x = Column('y', Integer, primary_key=True)? この場合、これらのソリューションはどれも機能しません。
Buttons840

13
drdaemanは右である、ここで正しいスニペットは次のとおりです。return {c.name: getattr(self, c.name) for c in self.__table__.columns}
charlax

5
この回答は無効な仮定をしています。列名は必ずしも属性名と一致するとは限りません。
RazerM 2016年

93

コメントの@zzzeekによると:

これはSQLAlchemyの最新バージョンの正しい答えであることに注意してください。「行」は、ORMにマップされたインスタンスではなく、コア行オブジェクトであると想定しています。

for row in resultproxy:
    row_as_dict = dict(row)

13
それはXXXのオブジェクトが反復可能ではない"と言い、私は0.5.6を使用しています、私はsession.queryにより取得する(クラース).filter()すべての()。
アヌラーグUniyal

60
これはSQLAlchemyの最新バージョンの正しい答えであることに注意してください。「行」は、ORMにマップされたインスタンスではなく、コア行オブジェクトであると想定しています。
zzzeek 2014年

48
また、zzzeekはsqlalchemyの作成者であることに注意してください。
クリス

1
誰でもこれについて詳しく説明できますか?私は初心者で、これを取得できません。
lameei

1
コア行オブジェクトとORMマップインスタンスの違いは何ですか?これは、query(MyModel).all():の行では機能しません。MyModelオブジェクトは反復可能ではありません。
ジョナサンハートレー

81

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ます。


@DukeDougalこれはv0.8(検査システムが追加されたとき)から機能すると思います。
RazerM 2016

1
これはSqlalchemy v2.0で動作します。他の答えはしません。
Thanh Nguyen

これは据え置きカラムを考慮していません
Mark

1
@マークデフォルトでは除外する必要があるかどうかは、はっきりしません。それでも、キーが入っていないことを確認できますsqlalchemy.inspect(obj).unloaded
RazerM

5
@NguyenThanh SQLAlchemy v2.0の操作は、存在しないことを考えると特に印象的です。最新の(ベータ)リリースはv1.3.0b1です。
マークアメリー

39

行には_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'}

プライベートであることが想定されており、将来のバージョンで削除/変更される可能性はありません。
Balki

2
@balki 十分に文書化されているため、非公開ではありません。先行アンダースコアは一般的にPythonではその意味を持っていますが、ここではおそらく、可能なタプルキーと競合しないようにするために使用されます。
IljaEverilä2017

5
これは、KeyedTupleでのみ機能します。これは、行の特定のフィールドをクエリするときにのみ返されます。つまり、.query(Topic.name)はKeyedTupleを返し、.query(Topic)は._asdict()のないトピックを返します-Derp。以下のSTBの回答を見たところです。
Chad Lowe

20

@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'}

PythonのORMクラス属性は、データベース列とは別の名前を持っている場合は、このソリューションを試してみてください。stackoverflow.com/questions/27947294/...
TaiwanGrapefruitTea

2
実際には、すべてのケースに対するより優れたソリューションは、sqlalchemyの作成者がstackoverflow.com/a/27948279/1023033
TaiwanGrapefruitTea

これを試してみると、ResultProxyオブジェクトに '_asdict'属性がありません
slashdottir

@slashdottir、クエリオブジェクトを実行しています.first()か(メソッドを呼び出しています)?
サム・ボーン

1
この回答は無効な仮定をしています。列名は必ずしも属性名と一致するわけではありません。
Piotr Dobrogost

18

古い質問ですが、これはGoogleの「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]

13
あなたはただすることができますlist_of_dicts = [dict(row.items()) for row in rows]
Markus Meskanen

1つの問題は、SQLAlchemyが結果セットで使用する列名がtable_name_column_nameであるということです。異なる名前が必要な場合(例:だけcolumn_name)、.labelメソッドを使用してください。session.query( MyTable.column_name.label('column_name'), ... )
Aneel、

こんにちは私はこの問題を取得していますplsは私を助けます* datetime.datetime(
2018、11、24、18、52、50

13

次の関数が次の関数に追加されると仮定すると、class Userすべての列のすべてのキーと値のペアが返されます。

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

他の回答とは異なり、オブジェクトのColumnクラスレベルの属性であるオブジェクトの属性のみが返されます。したがって、オブジェクトに追加されたSQLalchemy_sa_instance_stateその他の属性は含まれません。参照

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

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か、単に表示したくないためです。参照

Tipp all_orm_descriptorsは、hybrid_methodAssociationProxyも含めたい場合はそれらも返します。

他の回答へのコメント

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

(のようなすべての答えは12に基づいています)dict()関数はのみで動作SQLAlchemyのので返されたオブジェクトの行session.execute()のように、あなたが仕事に定義するクラスでないclass User質問から。

に基づく解答row.__table__.columnsは間違いなく機能しませんrow.__table__.columnsSQLデータベースの列名が含まれます。これらは、Pythonオブジェクトの属性名とのみ同じにすることができます。そうでない場合は、AttributeError。答え(のようなのために12に基づいて)class_mapper(obj.__class__).mapped_table.cそれと同じです。


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

4
local_tableとmapped_tableの違いに注意してください。たとえば、db(tbl_employees> tbl_managers、tbl_employees> tbl_staff)である種のテーブル継承を適用​​する場合、マップされたクラスはこれを反映する必要があります(Manager(Employee)、Staff(Employee))。mapped_table.cは、ベーステーブルと継承テーブルの両方の列名を提供します。local_tableは、(継承する)テーブルの名前のみを提供します。
Michael Ekoka

これにより、少なくともバージョン0.8以降では、「_ sa_instance_state」フィールドが提供されなくなります。
Evan Siroky 2013

4
この回答は無効な仮定をしています。列名は必ずしも属性名と一致するとは限りません。
RazerM 2016年

11

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

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

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

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


6
これは以前は本当だったかもしれませんが、SQLAlchemy v1.0 ではインスタンスの.all()リストが返されるUserため、これは機能しません。
RazerM 2016年

@RazerM、申し訳ありませんが、私はあなたの意味がわかりません。forループは、Userインスタンスのリストを正確にループし、それらを(u)辞書に変換してから印刷します...
jgbarah

3
Userインスタンスには_asdictメソッドがありません。gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8dを
RazerM

2
今それを手に入れました。ありがとう。KeyedTupleの代わりに、.all()がUserオブジェクトを返すようになりました。したがって、v1.0(およびそれ以上)の問題は、ユーザーオブジェクトから辞書を取得する方法です。説明をありがとう。
jgbarah 2016年

10

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

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()ます。


2
他のいくつかのコードはdictとしてデータを必要とするため、それらをdictに変換したいと思います。また、モデルオブジェクトの列がわからないため、一般的な方法が必要です
Anurag Uniyal

ハンドルを取得すると、モデルオブジェクトにしかアクセスできないため、session.executeなどを使用できません
Anurag Uniyal

8

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

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

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


1
@Greenonline確かに、承認コメントはAlex Brasetvikの回答の下にあります。彼の回答へのリンクを追加するために編集
NorWay

とはresultproxy
lameei

8

この方法でそれを試みることができます。

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

クエリオブジェクトの辞書オブジェクトを返すクエリオブジェクトの組み込みメソッドを使用します。

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


1
多分もっと説明を追加しますか?
Tiw

1
これ以上説明することはありません。これは、結果オブジェクトの組み込みメソッドです。したがって、これをすべての結果に対して行う場合でも、単一の行に対して行う場合でも_asdict()、フィールド名とフィールド値を圧縮して、結果を辞書として返す組み込みメソッドがあります。
マシュー

非常に簡潔で、私はそれが働いたが望むu私の場合、文字列がある、と私はモデル_asdict'` @hllau私のために働いた下記の「オブジェクトが属性を持っていない」 ``エラーが出る
モテZart

7

SQLAlchemyの行をdictに変換する方法を探していたため、この投稿を見つけました。私はSqlSoupを使用しています...しかし、答えは自分で作成したので、もしそれが誰かを助けることができれば、ここに私の2セントがあります。

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

# and now, finally...
dict(zip(c.keys(), c.values()))

1
または、必要に応じて..:[dict(zip(i(keys()、i.values()))for i in b]
Mychot sad

これが、実際に機能する唯一の構文です。私は1時間以上ものを試してきました。
slashdottir 2015

コア選択の場合、RowProxycこの回答の)はマッピングプロトコルに準拠しているため、を呼び出すだけdict(c)です。
RazerM 2016年

4

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)

3

二つの方法:

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

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

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

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

2

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

リンクが死んでいる。次回は、関連するコードもここにコピーしてください。
Gus E

次回はやります。私の記憶が正しければ、機能はかなり長くなりました。
argentpepper

2

このコードを使用して、クエリに「フィルター」または「結合」を追加して、この作業を行うこともできます。

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]

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

うまくいくはずです。


1
列名が「_」で始まる場合はどうなりますか?
Anurag Uniyal 2010

4
列に先頭にアンダースコアを付けてはいけないと思います。使用しても機能しません。ご存知のように奇妙な場合は、変更して列を追加できます。
2010

1

マルコマリアーニの答えを、デコレータとして表現したバリエーションがあります。主な違いは、エンティティのリストを処理するだけでなく、他のタイプの戻り値を安全に無視することです(モックを使用してテストを作成するときに非常に役立ちます)。

@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

@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):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    first_name = Column(TEXT)
    address_id = Column(Integer, ForeignKey('addresses.id')
    address = relationship('Address')

class Address(Base):
    __tablename__ = '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}

「with_relationships」のデフォルトがfalseに変更されている場合は、この値を再帰呼び出しに渡してください。例: d[relationship.key] = to_dict(val,with_relationships) if val else None
ニコラスハミルトン

address_id列に基づいてユーザーとアドレステーブルを結合し、ユーザーテーブルからすべての列をフェッチし、アドレステーブルからid列のみをフェッチする場合、どうすれば結果を得ることができますか。
Sudhakar

0

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

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

テスト= 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)

0

モデルテーブルの列が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を両方とも取得できます。

{'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

この: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

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

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

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


0

あなたはあなたのプロジェクトのどこでもそれを必要とするでしょう、私は@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

Python 3.8以降では、dataclass asdictとそれに付属するメソッドでこれを行うことができます。

from dataclasses import dataclass, asdict

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import Column, String, Integer, create_engine

Base = declarative_base()
engine = create_engine('sqlite:///:memory:', echo=False)


@dataclass
class User(Base):
    __tablename__ = 'users'

    id: int = Column(Integer, primary_key=True)
    name: str = Column(String)
    email = Column(String)

    def __init__(self, name):
        self.name = name
        self.email = 'hello@example.com'


Base.metadata.create_all(engine)

SessionMaker = sessionmaker(bind=engine)
session = SessionMaker()

user1 = User("anurag")
session.add(user1)
session.commit()

query_result = session.query(User).one()  # type: User
print(f'{query_result.id=:}, {query_result.name=:}, {query_result.email=:}')
# query_result.id=1, query_result.name=anurag, query_result.email=hello@example.com

query_result_dict = asdict(query_result)
print(query_result_dict)
# {'id': 1, 'name': 'anurag'}

重要なのは、@dataclassデコレータを使用して、各列にそのタイプ(注釈の: str一部)で注釈を付けることです。name: str = Column(String)行のです。

またemail、には注釈が付けられていないため、には含まれていませんquery_result_dict


Python3.7で「NameError:name 'asdict' is not defined」というメッセージが表示される
devnull

悪い!Python 3.8で追加された機能です。私の答えを修正しました。
toaruScar

-1

ほとんどのシナリオでは、列名はそれらに適しています。しかし、おそらく次のようにコードを記述します。

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

column.nameが「user_email」、フィールド名が「email」の場合、column.nameは以前と同じように機能しませんでした。

sqlalchemy_base_model.py

ここにも答えを書きます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.