Gibt es eine einfache Möglichkeit, über Spaltennamen- und Wertepaare zu iterieren?
Meine Version von sqlalchemy ist 0.5.6
Hier ist der Beispielcode, in dem ich versucht habe, dict (row) zu verwenden, aber er löst die Ausnahme TypeError aus: Das Objekt 'User' ist nicht iterierbar
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)
Ausführen dieses Codes auf meinen Systemausgaben:
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
python
sqlalchemy
Anurag Uniyal
quelle
quelle
sqlalchemy.util.KeyedTuple
die ist Zeilenobjekt aus dem Titel der Frage. Die Abfrage in der Frage verwendet jedoch die Modellklasse (zugeordnet), sodass der Typ des Zeilenobjekts die Modellklasse anstelle von istsqlalchemy.util.KeyedTuple
.Antworten:
Sie können auf das Interne
__dict__
eines SQLAlchemy-Objekts zugreifen , wie folgt:quelle
dictret = dict(row.__dict__); dictret.pop('_sa_instance_state', None)
__dict__
ein_sa_instance_state
Eintrag enthalten ist, der dann entfernt werden muss. Wenn Sie auf eine zukünftige Version aktualisieren und andere Attribute hinzugefügt werden, müssen Sie möglicherweise zurückgehen und diese manuell bearbeiten. Wenn Sie nur Spaltendaten möchten (z. B. um eine Liste von Instanzen aus einer Abfrage zu entnehmen und in einem Pandas-Datenrahmen abzulegen), erscheint{col.name: getattr(self, col.name) for col in self.__table__.columns}
die Antwort von Anurag Uniyal (mit wichtigen Korrekturen von Kommentaren zu dieser Antwort) sowohl prägnanter als auch fehlerhafter. Beweis.dict(u)
und gibt richtig an, dass sie a wirftTypeError
.Ich konnte keine gute Antwort bekommen und benutze diese:
Bearbeiten: Wenn die obige Funktion zu lang ist und für einige Geschmäcker nicht geeignet ist, ist hier ein Einzeiler (Python 2.7+)
quelle
return dict((col, getattr(row, col)) for col in row.__table__.columns.keys())
.row2dict = lambda row: dict((col, getattr(row, col)) for col in row.__table__.columns.keys())
, um es zu einem echten Einzeiler zu machen, aber ich bevorzuge, dass mein Code lesbar ist, horizontal kurz, vertikal langx = Column('y', Integer, primary_key=True)
? Keine dieser Lösungen funktioniert in diesem Fall.return {c.name: getattr(self, c.name) for c in self.__table__.columns}
Laut @zzzeek in Kommentaren:
quelle
query(MyModel).all()
: MyModel-Objekt nicht iterierbar.Verwenden Sie in SQLAlchemy v0.8 und höher das Inspektionssystem .
Beachten Sie, dass dies
.key
der Attributname ist, der sich vom Spaltennamen unterscheiden kann, z. B. im folgenden Fall:Diese Methode funktioniert auch für
column_property
.quelle
sqlalchemy.inspect(obj).unloaded
Zeilen haben eine
_asdict()
Funktion, die ein Diktat gibtquelle
wie @balki erwähnt:
Die
_asdict()
Methode kann verwendet werden, wenn Sie ein bestimmtes Feld abfragen, da es als KeyedTuple zurückgegeben wird .Wenn Sie keine Spalte angeben, können Sie eine der anderen vorgeschlagenen Methoden verwenden - beispielsweise die von @charlax bereitgestellte. Beachten Sie, dass diese Methode nur für 2.7+ gültig ist.
quelle
.first()
Methode auf)?Alte Frage, aber da dies das erste Ergebnis für "sqlalchemy row to dict" in Google ist, verdient es eine bessere Antwort.
Das von SqlAlchemy zurückgegebene RowProxy-Objekt verfügt über die Methode items (): http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items
Es wird einfach eine Liste von (Schlüssel-, Wert-) Tupeln zurückgegeben. So kann man eine Zeile wie folgt in ein Diktat umwandeln:
In Python <= 2.6:
In Python> = 2.7:
quelle
list_of_dicts = [dict(row.items()) for row in rows]
table_name_column_name
, wenn Sie andere Namen möchten (z. B. nurcolumn_name
).label
.session.query( MyTable.column_name.label('column_name'), ... )
Angenommen, die folgenden Funktionen werden zu den folgenden hinzugefügt,
class User
werden alle Schlüssel-Wert-Paare aller Spalten zurückgegeben:Im Gegensatz zu den anderen Antworten werden alle Attribute außer dem Objekt zurückgegeben, bei denen es sich um
Column
Attribute auf Klassenebene des Objekts handelt. Daher sind keine_sa_instance_state
oder andere Attribute SQLalchemy oder Sie, die Sie dem Objekt hinzufügen, enthalten. ReferenzEDIT: Vergessen Sie zu sagen, dass dies auch für geerbte Spalten funktioniert.
hybrid_propery
VerlängerungWenn Sie auch
hybrid_property
Attribute einschließen möchten, funktioniert Folgendes:Ich gehe hier davon aus, dass Sie Spalten mit einem Anfang
_
markieren, um anzuzeigen, dass Sie sie ausblenden möchten, entweder weil Sie über ein auf das Attribut zugreifenhybrid_property
oder weil Sie sie einfach nicht anzeigen möchten . ReferenzTipp gibt
all_orm_descriptors
auch hybrid_method und AssociationProxy zurück, wenn Sie sie ebenfalls einschließen möchten.Anmerkungen zu anderen Antworten
Jede Antwort (wie 1 , 2 ), die auf dem
__dict__
Attribut basiert , gibt einfach alle Attribute des Objekts zurück. Dies können viel mehr Attribute sein, als Sie möchten. Wie ich traurig finde, enthält dies_sa_instance_state
oder jedes andere Attribut, das Sie für dieses Objekt definieren.Jede Antwort (wie 1 , 2 ), die auf der
dict()
Funktion basiert, funktioniert nur mit SQLalchemy-Zeilenobjekten, die vonsession.execute()
nicht den Klassen zurückgegeben werden, mit denen Sie arbeiten möchten , wie z. B.class User
aus der Frage.Die Antwort auf die Lösung, auf der basiert,
row.__table__.columns
wird definitiv nicht funktionieren.row.__table__.columns
enthält die Spaltennamen der SQL-Datenbank. Diese können nur dem Attributnamen des Python-Objekts entsprechen. Wenn nicht, bekommst du eineAttributeError
. Für Antworten (wie 1 , 2 ), die darauf basierenclass_mapper(obj.__class__).mapped_table.c
, ist es dasselbe.quelle
quelle
Nach der Antwort von @balki können Sie seit SQLAlchemy 0.8 _asdict () verwenden, das für KeyedTuple-Objekte verfügbar ist. Dies ergibt eine ziemlich einfache Antwort auf die ursprüngliche Frage. Ändern Sie in Ihrem Beispiel einfach die letzten beiden Zeilen (die for-Schleife) für diese:
Dies funktioniert, weil im obigen Code u ein Objekt der Typklasse KeyedTuple ist , da .all () eine Liste von KeyedTuple zurückgibt. Daher hat es die Methode _asdict () , die u schön als Wörterbuch zurückgibt.
WRT die Antwort von @STB: AFAIK, obwohl .all () eine Liste von KeypedTuple zurückgibt. Daher funktioniert das Obige entweder, wenn Sie eine Spalte angeben oder nicht, solange Sie sich mit dem Ergebnis von .all () befassen, das auf ein Abfrageobjekt angewendet wird.
quelle
.all()
derUser
Fall gewesen sein, aber unter SQLAlchemy v1.0 wird eine Liste von Instanzen zurückgegeben, sodass dies nicht funktioniert.User
Instanzen haben keine_asdict
Methode. Siehe gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8dDer Ausdruck, den Sie durchlaufen, wird zu einer Liste von Modellobjekten und nicht zu Zeilen ausgewertet . Das Folgende ist also die richtige Verwendung von ihnen:
Müssen Sie sie wirklich in Diktate umwandeln? Sicher, es gibt viele Möglichkeiten, aber dann brauchen Sie keinen ORM-Teil von SQLAlchemy:
Update : Schauen Sie sich das
sqlalchemy.orm.attributes
Modul an. Es verfügt über eine Reihe von Funktionen zum Arbeiten mit dem Objektstatus, die insbesondere für Sie nützlich sein könneninstance_dict()
.quelle
In der Antwort von Alex Brasetvik können Sie eine Codezeile verwenden, um das Problem zu lösen
Im Kommentarbereich von Alex Brasetviks Antwort erklärte zzzeek, der Schöpfer von SQLAlchemy, dies sei die "richtige Methode" für das Problem.
quelle
resultproxy
?Sie könnten versuchen, es auf diese Weise zu tun.
Es verwendet eine im Abfrageobjekt integrierte Methode, die ein diktonisches Objekt des Abfrageobjekts zurückgibt.
Referenzen: https://docs.sqlalchemy.org/en/latest/orm/query.html
quelle
_asdict()
Methode, die die Feldnamen im Wesentlichen mit Feldwerten komprimiert und das Ergebnis als Wörterbuch zurückgibt.u
in meinem Fall ist eine Zeichenfolge, und ich bekomme Fehler `` Modell ‚Objekt hat kein Attribut‘ _asdict'` @hllau unten für mich gearbeitetIch habe diesen Beitrag gefunden, weil ich nach einer Möglichkeit gesucht habe, eine SQLAlchemy-Zeile in ein Diktat umzuwandeln. Ich benutze SqlSoup ... aber die Antwort wurde von mir selbst erstellt. Wenn es jemandem helfen könnte, sind hier meine zwei Cent:
quelle
RowProxy
(c
in dieser Antwort) an das Zuordnungsprotokoll, sodass Sie einfach anrufen könnendict(c)
.Sie können das sqlalchemy-Objekt wie folgt in ein Wörterbuch konvertieren und es als json / dictionary zurückgeben.
Hilfsfunktionen:
Treiberfunktion:
quelle
Zwei Wege:
1.
2.
quelle
Die Dokumente bieten eine sehr einfache Lösung:
ResultRow._asdict()
quelle
So macht es Elixir. Der Wert dieser Lösung besteht darin, dass sie die rekursive Einbeziehung der Wörterbuchdarstellung von Beziehungen ermöglicht.
quelle
Mit diesem Code können Sie Ihrer Abfrage auch "Filter" oder "Join" hinzufügen und diese Arbeit!
quelle
Das sollte funktionieren.
quelle
Ich habe eine Variation von Marco Marianis Antwort, ausgedrückt als Dekorateur. Der Hauptunterschied besteht darin, dass Listen von Entitäten verarbeitet und einige andere Arten von Rückgabewerten ignoriert werden (was beim Schreiben von Tests mit Mocks sehr nützlich ist):
quelle
Um die Antwort von @Anurag Uniyal zu vervollständigen, folgt eine Methode, die rekursiv Beziehungen folgt:
quelle
d[relationship.key] = to_dict(val,with_relationships) if val else None
Ich bin ein neu geprägter Python-Programmierer und hatte Probleme, mit verbundenen Tabellen zu JSON zu gelangen. Unter Verwendung der Informationen aus den Antworten hier habe ich eine Funktion erstellt, um angemessene Ergebnisse an JSON zurückzugeben, in der die Tabellennamen enthalten sind, ohne dass ein Alias erforderlich ist oder Felder kollidieren.
Übergeben Sie einfach das Ergebnis einer Sitzungsabfrage:
test = Session (). query (VMInfo, Kunde) .join (Kunde) .order_by (VMInfo.vm_name) .limit (50) .offset (10)
json = sqlAl2json (Test)
quelle
Wenn Ihre Modelltabellenspalte nicht der MySQL-Spalte entspricht.
sowie :
Benötigt werden:
Wenn Sie diese Methode verwenden, können Sie "modify_time" und "create_time" abrufen. Beide sind "None"
Weil der Name der Klassenattribute nicht mit dem Spaltenspeicher in MySQL übereinstimmt
quelle
Geben Sie den Inhalt dieser: class:
.KeyedTuple
als Wörterbuch zurückquelle
Für alle und mich selbst benutze ich Folgendes:
quelle
Diese Funktion könnte helfen. Ich kann keine bessere Lösung finden, um das Problem zu lösen, wenn sich der Attributname von den Spaltennamen unterscheidet.
quelle
Sie werden es überall in Ihrem Projekt brauchen. Ich schätze @anurag antwortete, dass es gut funktioniert. Bis zu diesem Punkt habe ich es verwendet, aber es wird Ihren gesamten Code durcheinander bringen und auch nicht mit Entitätsänderungen funktionieren.
Versuchen Sie dies lieber und erben Sie Ihre Basisabfrageklasse in SQLAlchemy
Danach ist überall dort, wo Sie Ihr Objekt definieren, die Methode "as_dict" vorhanden.
quelle
Mit Python 3.8+ können wir dies mit der Datenklasse und der damit verbundenen
asdict
Methode tun :Der Schlüssel besteht darin, den
@dataclass
Dekorator zu verwenden und jede Spalte mit ihrem Typ (dem: str
Teil dername: str = Column(String)
Zeile) zu versehen.Beachten Sie auch, dass das
email
nicht mit Anmerkungen versehen ist und nicht in enthalten istquery_result_dict
.quelle
In den meisten Szenarien ist der Spaltenname für sie geeignet. Aber vielleicht schreiben Sie den Code wie folgt:
Der Spaltenname "user_email", während der Feldname "email" lautet, konnte der Spaltenname nicht wie zuvor funktionieren.
sqlalchemy_base_model.py
auch ich schreibe die antwort hier
quelle