396 Stimmen

Wie konvertiert man ein SQLAlchemy-Zeilenobjekt in ein Python-Diktat?

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, mit dict(row) :

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)

Die Ausführung dieses Codes auf meinem System ergibt:

Traceback (most recent call last):
  File "untitled-1.py", line 37, in <module>
    print dict(u)
TypeError: 'User' object is not iterable

34voto

F.Raab Punkte 693

Angenommen, die folgenden Funktionen werden in die class User werden im Folgenden alle Schlüssel-Wert-Paare aller Spalten zurückgegeben:

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

Im Gegensatz zu den anderen Antworten werden alle, aber nur die Attribute des Objekts zurückgegeben, die Column Attribute auf Klassenebene des Objekts. Daher keine _sa_instance_state oder jedes andere Attribut SQLalchemy oder die Sie dem Objekt hinzufügen, sind enthalten. Referenz

EDIT: Ich vergaß zu erwähnen, dass dies auch bei geerbten Spalten funktioniert.

hybrid_property Erweiterung

Wenn Sie außerdem Folgendes aufnehmen möchten hybrid_property Attribute werden die folgenden funktionieren:

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_

Ich gehe hier davon aus, dass Sie Columns mit einem Anfang markieren _ um anzuzeigen, dass Sie sie ausblenden wollen, entweder weil Sie auf das Attribut über eine hybrid_property oder Sie wollen sie einfach nicht zeigen. Referenz

Tipp all_orm_descriptors gibt auch zurück hybrides_Verfahren y AssociationProxy wenn Sie diese ebenfalls einbeziehen möchten.

Anmerkungen zu anderen Antworten

Jede Antwort (wie 1 , 2 ), die auf der Grundlage des __dict__ Attribut gibt einfach alle Attribute des Objekts zurück. Das können viel mehr Attribute sein, als Sie wollen. Wie ich traurig bin, beinhaltet dies _sa_instance_state oder jedes andere Attribut, das Sie für dieses Objekt definieren.

Jede Antwort (wie 1 , 2 ), die sich auf die dict() Funktion funktioniert nur bei SQLalchemy Zeilenobjekte, die von session.execute() nicht auf die Klassen, die Sie für die Arbeit definieren, wie die class User aus der Frage.

En lösende Antwort die sich auf row.__table__.columns wird definitiv no Arbeit. row.__table__.columns enthält die Spaltennamen der SQL-Datenbank. Diese kann nur gleich dem Attributnamen des Python-Objekts sein. Wenn nicht, erhalten Sie eine AttributeError . Für Antworten (wie 1 , 2 ) basierend auf class_mapper(obj.__class__).mapped_table.c ist es dasselbe.

31voto

Sam Bourne Punkte 540

Wie @balki erwähnte:

En _asdict() Methode kann verwendet werden, wenn Sie ein bestimmtes Feld abfragen, da es als KeyedTuple .

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

Wenn Sie hingegen keine Spalte angeben, können Sie eine der anderen vorgeschlagenen Methoden verwenden, z. B. die von @charlax bereitgestellte. Beachten Sie, dass diese Methode nur für 2.7+ gültig ist.

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

21voto

fgasparini Punkte 1238

Alte Frage, aber da dies das erste Ergebnis für "sqlalchemy row to dict" in Google ist, verdient es eine bessere Antwort.

Das RowProxy-Objekt, das SqlAlchemy zurückgibt, hat die Methode items(): http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

Sie gibt einfach eine Liste von (Schlüssel, Wert) Tupeln zurück. Man kann also eine Zeile in ein Diktat umwandeln, indem man folgendes tut:

In Python <= 2.6:

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

In Python >= 2.7:

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

16voto

yellow-saint Punkte 798

Eine sehr einfache Lösung: row._asdict() .

15voto

slav0nic Punkte 3244

Mit Sqlalchemy 1.4

session.execute(select(User.id, User.username)).mappings().all()
>> [{'id': 1, 'username': 'Bob'}, {'id': 2, 'username': 'Alice'}]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X