Existe-t-il un moyen simple d'itérer les paires nom de colonne et valeur?
Ma version de sqlalchemy est 0.5.6
Voici l'exemple de code où j'ai essayé d'utiliser dict (row), mais il lève une exception, TypeError: l'objet 'User' n'est pas itérable
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)
Exécuter ce code sur mes sorties système:
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
la source
la source
sqlalchemy.util.KeyedTuple
qui est l' objet de la ligne du titre de la question. Cependant, la requête dans la question utilise la classe modèle (mappée), donc le type d' objet de ligne est la classe modèle au lieu desqlalchemy.util.KeyedTuple
.Réponses:
Vous pouvez accéder à l'intérieur
__dict__
d'un objet SQLAlchemy, comme suit:la source
dictret = dict(row.__dict__); dictret.pop('_sa_instance_state', None)
__dict__
une_sa_instance_state
entrée doit être supprimée. si vous passez à une version future et que d'autres attributs sont ajoutés, vous devrez peut-être revenir en arrière et les traiter manuellement. si vous voulez juste des données de colonne (par exemple, pour prendre une liste d'instances d'une requête et les déposer dans une trame de données pandas) alors{col.name: getattr(self, col.name) for col in self.__table__.columns}
comme répondu par Anurag Uniyal (avec des corrections importantes des commentaires à cette réponse) semble à la fois plus succinct et erreur- preuve.dict(u)
et déclare correctement qu'elle jette aTypeError
.Je n'ai pas pu obtenir une bonne réponse, donc j'utilise ceci:
Edit: si la fonction ci-dessus est trop longue et ne convient pas à certains goûts voici un one liner (python 2.7+)
la source
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())
pour en faire un vrai liner, mais je préfère que mon code soit lisible, horizontalement court, verticalement longx = Column('y', Integer, primary_key=True)
? Aucune de ces solutions ne fonctionne dans ce cas.return {c.name: getattr(self, c.name) for c in self.__table__.columns}
Selon @zzzeek dans les commentaires:
la source
query(MyModel).all()
: l' objet MyModel n'est pas itérable.Dans SQLAlchemy v0.8 et plus récent, utilisez le système d'inspection .
Notez qu'il
.key
s'agit du nom de l'attribut, qui peut être différent du nom de la colonne, par exemple dans le cas suivant:Cette méthode fonctionne également pour
column_property
.la source
sqlalchemy.inspect(obj).unloaded
les lignes ont une
_asdict()
fonction qui donne un dictla source
comme @balki l'a mentionné:
La
_asdict()
méthode peut être utilisée si vous interrogez un champ spécifique car il est renvoyé en tant que KeyedTuple .Alors que si vous ne spécifiez pas de colonne, vous pouvez utiliser l'une des autres méthodes proposées - comme celle fournie par @charlax. Notez que cette méthode n'est valide que pour la version 2.7+.
la source
.first()
méthode)?Vieille question, mais comme c'est le premier résultat pour "sqlalchemy row to dict" dans Google, il mérite une meilleure réponse.
L'objet RowProxy que SqlAlchemy renvoie a la méthode items (): http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items
Il retourne simplement une liste de tuples (clé, valeur). On peut donc convertir une ligne en dict en utilisant ce qui suit:
En Python <= 2.6:
En Python> = 2,7:
la source
list_of_dicts = [dict(row.items()) for row in rows]
table_name_column_name
, si vous voulez des noms différents (par exemple justecolumn_name
), utilisez la.label
méthode.session.query( MyTable.column_name.label('column_name'), ... )
En supposant que les fonctions suivantes seront ajoutées à la
class User
suivante, toutes les paires valeur / clé de toutes les colonnes seront renvoyées:contrairement aux autres réponses, tous les attributs de l'objet sont renvoyés, mais uniquement ceux qui sont des
Column
attributs au niveau de la classe de l'objet. Par conséquent, aucun_sa_instance_state
ou tout autre attribut SQLalchemy ou que vous ajoutez à l'objet n'est inclus. RéférenceEDIT: Oubliez de dire que cela fonctionne également sur les colonnes héritées.
hybrid_propery
extentionSi vous souhaitez également inclure des
hybrid_property
attributs, les éléments suivants fonctionneront:Je suppose ici que vous marquez les colonnes avec un début
_
pour indiquer que vous souhaitez les masquer, soit parce que vous accédez à l'attribut parhybrid_property
ou vous ne voulez tout simplement pas les afficher. RéférenceTipp
all_orm_descriptors
renvoie également hybrid_method et AssociationProxy si vous souhaitez également les inclure.Remarques sur d'autres réponses
Chaque réponse (comme 1 , 2 ) qui, sur la base de l'
__dict__
attribut, renvoie simplement tous les attributs de l'objet. Cela pourrait être beaucoup plus d'attributs que vous le souhaitez. Comme je le regrette, cela inclut_sa_instance_state
ou tout autre attribut que vous définissez sur cet objet.Chaque réponse (comme 1 , 2 ) basée sur la
dict()
fonction ne fonctionne que sur les objets de ligne SQLalchemy renvoyés parsession.execute()
les classes que vous définissez pour travailler, commeclass User
dans la question.La réponse de résolution basée sur
row.__table__.columns
ne fonctionnera certainement pas .row.__table__.columns
contient les noms de colonne de la base de données SQL. Ceux- ci ne peuvent être égaux qu'au nom d'attributs de l'objet python. Sinon, vous obtenez unAttributeError
. Pour les réponses (comme 1 , 2 ) basées surclass_mapper(obj.__class__).mapped_table.c
c'est la même chose.la source
la source
Suite à la réponse de @balki, depuis SQLAlchemy 0.8, vous pouvez utiliser _asdict (), disponible pour les objets KeyedTuple. Cela rend une réponse assez simple à la question d'origine. Modifiez simplement dans votre exemple les deux dernières lignes (la boucle for) pour celle-ci:
Cela fonctionne parce que dans le code ci-dessus, u est un objet de type classe KeyedTuple , car .all () renvoie une liste de KeyedTuple. Par conséquent, il a la méthode _asdict () , qui retourne joliment u en tant que dictionnaire.
WRT la réponse de @STB: AFAIK, une fois que .all () retourne est une liste de KeypedTuple. Par conséquent, ce qui précède fonctionne si vous spécifiez une colonne ou non, tant que vous traitez le résultat de .all () appliqué à un objet Query.
la source
.all()
renvoie une liste d'User
instances, donc cela ne fonctionne pas.User
les instances n'ont pas de_asdict
méthode. Voir gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8dL'expression que vous parcourez évalue la liste des objets du modèle , pas les lignes. Ainsi, leur utilisation est correcte:
Avez-vous vraiment besoin de les convertir en dict? Bien sûr, il existe de nombreuses façons, mais vous n'avez pas besoin de la partie ORM de SQLAlchemy:
Mise à jour : jetez un œil au
sqlalchemy.orm.attributes
module. Il dispose d'un ensemble de fonctions pour travailler avec l'état de l'objet, qui pourraient vous être utiles, en particulierinstance_dict()
.la source
Référez-vous à la réponse d'Alex Brasetvik , vous pouvez utiliser une ligne de code pour résoudre le problème
Dans la section des commentaires de la réponse d'Alex Brasetvik, zzzeek, le créateur de SQLAlchemy, a déclaré que c'était la "bonne méthode" pour le problème.
la source
resultproxy
?Vous pouvez essayer de le faire de cette façon.
Il utilise une méthode intégrée dans l'objet de requête qui renvoie un objet dictonary de l'objet de requête.
références: https://docs.sqlalchemy.org/en/latest/orm/query.html
la source
_asdict()
méthode intégrée qui zippe essentiellement les noms de champ avec des valeurs de champ et renvoie le résultat sous forme de dictionnaire.u
dans mon cas, c'est une chaîne et j'obtiens l'erreur `` L'objet du modèle n'a pas d'attribut '_asdict' '@hllau ci-dessous a fonctionné pour moiJ'ai trouvé ce message parce que je cherchais un moyen de convertir une ligne SQLAlchemy en dict. J'utilise SqlSoup ... mais la réponse a été construite par moi-même, donc, si cela peut aider quelqu'un, voici mes deux cents:
la source
RowProxy
(c
dans cette réponse) adhère au protocole de mappage, vous pouvez donc simplement appelerdict(c)
.Vous pouvez convertir un objet sqlalchemy en dictionnaire comme celui-ci et le renvoyer en tant que json / dictionary.
Fonctions d'assistance:
Fonction pilote:
la source
Deux manières:
1.
2.
la source
Les documents offrent une solution très simple:
ResultRow._asdict()
la source
Voici comment Elixir le fait. L'intérêt de cette solution est qu'elle permet d'inclure récursivement la représentation dictionnaire des relations.
la source
Avec ce code, vous pouvez également ajouter à votre requête "filtre" ou "rejoindre" et ce travail!
la source
Cela devrait fonctionner.
la source
J'ai une variation sur la réponse de Marco Mariani, exprimée en tant que décorateur. La principale différence est qu'il gère les listes d'entités, tout en ignorant en toute sécurité certains autres types de valeurs de retour (ce qui est très utile lors de l'écriture de tests à l'aide de mocks):
la source
Pour compléter la réponse de @Anurag Uniyal, voici une méthode qui suivra récursivement les relations:
la source
d[relationship.key] = to_dict(val,with_relationships) if val else None
Avec python 3.8+, nous pouvons le faire avec la classe de données et la
asdict
méthode qui l'accompagne:L'essentiel est d'utiliser le
@dataclass
décorateur et d'annoter chaque colonne avec son type (la: str
partie de laname: str = Column(String)
ligne).Notez également que puisque le
email
n'est pas annoté, il n'est pas inclus dansquery_result_dict
.la source
Je suis un programmeur Python nouvellement créé et j'ai rencontré des problèmes pour accéder à JSON avec les tables jointes. En utilisant les informations des réponses ici, j'ai construit une fonction pour renvoyer des résultats raisonnables à JSON où les noms de table sont inclus en évitant d'avoir à créer un alias ou à faire entrer les champs en collision.
Passez simplement le résultat d'une requête de session:
test = Session (). query (VMInfo, Customer) .join (Customer) .order_by (VMInfo.vm_name) .limit (50) .offset (10)
json = sqlAl2json (test)
la source
si la colonne de votre table de modèles n'est pas la colonne equie mysql.
tel que :
Besoin d'utiliser:
si vous utilisez cette méthode, vous pouvez obtenir modify_time et create_time les deux sont None
Parce que le nom des attributs de classe n'est pas égal au magasin de colonnes dans mysql
la source
Renvoie le contenu de ceci: classe:
.KeyedTuple
sous forme de dictionnairela source
Pour le bien de tous et de moi-même, voici comment je l'utilise:
la source
Cette fonction pourrait aider. Je ne peux pas trouver de meilleure solution pour résoudre le problème lorsque le nom d'attribut est différent des noms de colonne.
la source
Vous en aurez besoin partout dans votre projet, je apriciate @anurag a répondu que cela fonctionne bien. jusqu'à présent, je l'utilisais, mais il gâchera tout votre code et ne fonctionnera pas non plus avec le changement d'entité.
Essayez plutôt ceci, héritez de votre classe de requête de base dans SQLAlchemy
après cela, partout où vous définirez votre méthode d'objet "as_dict" sera là.
la source
Dans la plupart des scénarios, le nom de la colonne leur convient. Mais peut-être que vous écrivez le code comme suit:
le column.name "user_email" tandis que le nom du champ est "email", le column.name ne pouvait pas bien fonctionner comme avant.
sqlalchemy_base_model.py
aussi j'écris la réponse ici
la source