Преобразовать объект строки sqlalchemy в python dict - PullRequest
199 голосов
/ 24 декабря 2009

Существует ли простой способ перебора пар столбцов с именами и значениями?

Моя версия sqlalchemy - 0.5.6

Вот пример кода, где я пытался использовать dict (строку), но он выдает исключение, TypeError: объект «Пользователь» не повторяется

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

Ответы [ 32 ]

202 голосов
/ 29 апреля 2012

Вы можете получить доступ к внутреннему __dict__ объекта SQLAlchemy, например:

for u in session.query(User).all():
    print u.__dict__
128 голосов
/ 25 декабря 2009

Я не мог получить хороший ответ, поэтому я использую это:

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}
65 голосов
/ 20 мая 2016

В 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.

63 голосов
/ 24 декабря 2009
for row in resultproxy:
    row_as_dict = dict(row)
32 голосов
/ 09 января 2014

строк имеют функцию _asdict(), которая дает dict

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'}
17 голосов
/ 15 июля 2014

как упомянул @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'}
15 голосов
/ 28 октября 2016

Старый вопрос, но так как это первый результат для "sqlalchemy row to dict" в Google, он заслуживает лучшего ответа.

Объект RowProxy, который возвращает SqlAlchemy, имеет метод items (): http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

Он просто возвращает список (ключ, значение) кортежей. Таким образом, можно преобразовать строку в dict, используя следующее:

В Python <= 2,6: </p>

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]
12 голосов
/ 16 марта 2010
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)
10 голосов
/ 22 августа 2014

После ответа @balki, начиная с SQLAlchemy 0.8 , вы можете использовать _asdict (), доступный для объектов KeyedTuple. Это дает довольно простой ответ на оригинальный вопрос. Просто измените в вашем примере две последние строки (цикл for) на эту:

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

Это работает, потому что в приведенном выше коде u является объектом типа класса KeyedTuple , поскольку .all () возвращает список KeyedTuple. Поэтому он имеет метод _asdict () , который приятно возвращает вас в качестве словаря.

WRT ответ от @STB: AFAIK, несмотря на то, что .all () возвращает список KeypedTuple. Следовательно, вышеприведенное работает либо в том случае, если вы укажете столбец, либо нет, если вы имеете дело с результатом .all () применительно к объекту Query.

9 голосов
/ 17 мая 2015

Предполагая, что следующие функции будут добавлены к 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 или вы просто не хотите их показывать. Ссылка

Тип all_orm_descriptors также возвращает hybrid_method и AssociationProxy , если вы также хотите включить их.

Замечания к другим ответам

Каждый ответ (например, 1 , 2 ), основанный на атрибуте __dict__, просто возвращает все атрибуты объекта. Это может быть гораздо больше атрибутов, чем вы хотите. Как мне грустно, это включает _sa_instance_state или любой другой атрибут, который вы определяете для этого объекта.

Каждый ответ (например, 1 , 2 ), основанный на функции dict(), работает только на SQLalchemy объектах строк, возвращаемых session.execute() not на классах, с которыми вы работаете, например, class User из вопроса.

Решающий ответ , основанный на row.__table__.columns, определенно не будет работать. row.__table__.columns содержит имена столбцов базы данных SQL. Эти могут быть только равными имени атрибута объекта python. Если нет, вы получите AttributeError. Для ответов (например, 1 , 2 ), основанных на class_mapper(obj.__class__).mapped_table.c, то же самое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...