列名と値のペアを反復処理する簡単な方法はありますか?
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
良い答えが得られなかったので、これを使用します:
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}
次のように、SQLAlchemyオブジェクトの内部__dict__
にアクセスできます。
for u in session.query(User).all():
print u.__dict__
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
でも機能します。
for row in resultproxy:
row_as_dict = dict(row)
行には、辞書を与える_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が述べたように:
特定のフィールドが 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'}
古い質問ですが、これは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]
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)
@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()の結果を処理している限り、列を指定するかどうかにかかわらず、上記は機能します。
以下の関数が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_descriptors
も hybrid_method および AssociationProxy も返します。
__dict__
属性に基づくすべての回答( 1 、 2 など)は、オブジェクトのすべての属性を単に返します。これは、必要な属性よりもはるかに多くなる可能性があります。悲しいことに、これには_sa_instance_state
またはこのオブジェクトで定義する他の属性が含まれます。
dict()
関数に基づくすべての回答( 1 、 2 など)は、session.execute()
によって返されるSQLalchemy行オブジェクトでのみ機能します質問のclass User
のように、操作するように定義したクラスではありません。
row.__table__.columns
に基づく 解答 は間違いなくnot動作します。 row.__table__.columns
には、SQLデータベースの列名が含まれます。これらは、pythonオブジェクトの属性名とのみ同じにすることができます。そうでない場合は、AttributeError
を取得します。 class_mapper(obj.__class__).mapped_table.c
に基づく回答( 1 、 2 など)の場合も同じです。
繰り返し処理する式は、行ではなくモデルオブジェクトのリストに評価されます。したがって、以下はそれらの正しい使用法です。
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()
に役立ちます。
Alex Brasetvik's Answer を参照してください。1行のコードを使用して問題を解決できます。
row_as_dict = [dict(row) for row in resultproxy]
Alex Brasetvikの回答のコメントセクションで、SQLAlchemyの作成者であるzzzeekは、これが問題の「正しい方法」であると述べました。
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()))
この方法で試してみることができます。
for u in session.query(User).all():
print(u._asdict())
クエリオブジェクトの組み込みオブジェクトを使用して、クエリオブジェクトの辞書オブジェクトを返します。
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)
二通り:
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())
ドキュメントは非常にシンプルなソリューションを提供します: ResultRow._asdict()
def to_array(rows):
return [r._asdict() for r in rows]
def query():
data = session.query(Table).all()
return to_array(data)
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
このコードを使用すると、クエリに「フィルター」または「結合」を追加することもできます!
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]
マルコ・マリアーニの答えにはバリエーションがあり、デコレーターとして表現されています。主な違いは、エンティティの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
class User(object):
def to_dict(self):
return dict([(k, getattr(self, k)) for k in self.__dict__.keys() if not k.startswith("_")])
うまくいくはずです。
この: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'}
モデルテーブルの列が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の列ストアと等しくないため
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}
あなたはプロジェクトのどこでもそれを必要とします、私は@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」メソッドを定義する場所はどこにでもあります。
みんなと私のために、私はそれをどのように使用するかです:
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]
私は新しく造られた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)