Преобразование объекта строки sqlalchemy в python dict

Есть ли простой способ перебора пар имен столбцов и значений?

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

Вот пример кода, в котором я пытался использовать dict (row), но он вызывает исключение, 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

Ответ 1

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

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}

Ответ 2

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

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

Ответ 3

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

Ответ 4

Согласно @zzzeek в комментариях:

обратите внимание, что это правильный ответ для современных версий SQLAlchemy, предполагая, что "строка" является базовым объектом строки, а не сопоставленным с ORM Экземпляр.

for row in resultproxy:
    row_as_dict = dict(row)

Ответ 5

Строки

имеют функцию _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'}

Ответ 6

как упоминал @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'}

Ответ 7

Старый вопрос, но поскольку это первый результат для "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:

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]

Ответ 8

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)

Ответ 9

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

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

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

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

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

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

Ответ 10

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

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

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

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

Ответ 11

Выражение, которое вы повторяете, вычисляет список объектов модели, а не строк. Поэтому правильное их использование:

for u in session.query(User).all():
    print u.id, u.name

Вам действительно нужно преобразовать их в dicts? Конечно, есть много способов, но тогда вам не нужна ORM-часть SQLAlchemy:

result = session.execute(User.__table__.select())
for row in result:
    print dict(row)

Обновить. Посмотрите на модуль sqlalchemy.orm.attributes. Он имеет набор функций для работы с состоянием объекта, который может быть вам полезен, особенно instance_dict().

Ответ 12

Я нашел этот пост, потому что искал способ преобразования строки SQLAlchemy в dict. Я использую SqlSoup... но ответ был построен сам, поэтому, если он может помочь кому-то здесь, мои два цента:

a = db.execute('select * from acquisizioni_motes')
b = a.fetchall()
c = b[0]

# and now, finally...
dict(zip(c.keys(), c.values()))

Ответ 13

Обратитесь к Alex Brasetvik Answer, вы можете использовать одну строку кода для решения проблемы

row_as_dict = [dict(row) for row in resultproxy]

В разделе комментариев Alex Brasetvik Ответ, zzzeek, ​​создатель SQLAlchemy заявил, что это "правильный метод" для проблемы.

Ответ 14

Вы можете попытаться сделать это таким образом.

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

Он использует встроенный метод в объекте запроса, который возвращает диктонарный объект объекта запроса.

ссылки: https://docs.sqlalchemy.org/en/latest/orm/query.html

Ответ 15

Вы можете преобразовать объект 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)

Ответ 16

Два пути:

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())

Ответ 17

Документы предлагают очень простое решение: ResultRow._asdict()

def to_array(rows):
    return [r._asdict() for r in rows]

def query():
    data = session.query(Table).all()
    return to_array(data)

Ответ 18

Вот как это делает Эликсир. Значение этого решения заключается в том, что оно позволяет рекурсивно включать в себя словарное представление отношений.

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

Ответ 19

С помощью этого кода вы также можете добавить к вашему запросу "фильтр" или "присоединиться" и эту работу!

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]

Ответ 20

class User(object):
    def to_dict(self):
        return dict([(k, getattr(self, k)) for k in self.__dict__.keys() if not k.startswith("_")])

Это должно работать.

Ответ 21

У меня есть вариант ответа Марко Мариани, выраженный в качестве декоратора. Основное отличие состоит в том, что он будет обрабатывать списки объектов, а также безопасно игнорировать некоторые другие типы возвращаемых значений (что очень полезно при написании тестов с использованием mocks):

@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

Ответ 22

Чтобы завершить ответ @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):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    first_name = Column(TEXT)
    address_id = Column(Integer, ForeignKey('addresses.id')
    address = relationship('Address')

class Address(Base):
    __tablename__ = '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}

Ответ 23

Самый простой способ, который я нашел (используя sqla 0.7.8):

dictlist = [dict(row) for row in somequery.execute().fetchall()]

Ответ 24

Я новый программируемый программист на Python и столкнулся с проблемами, связанными с JSON с добавленными таблицами. Используя информацию из ответов здесь, я построил функцию, чтобы возвращать разумные результаты JSON, где включены имена таблиц, избегая наличия псевдонима или поля сталкиваются.

Просто передайте результат запроса сеанса:

test = Session(). query (VMInfo, Customer).join(Customer).order_by (VMInfo.vm_name).limit(50).offset(10)

json = sqlAl2json (тест)

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)

Ответ 25

если столбец вашей модели не является эквивалентным столбцом 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}

если вы используете этот способ, вы можете получить change_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

Ответ 26

Вернуть содержимое этого: 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'}

Ответ 27

Ради всех и меня, вот как я его использую:

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]

Ответ 28

__dict__ без внутренних (подчеркнутых) атрибутов может быть использовано в качестве быстрого решения.

for u in session.query(User).all():
     print({k: v for k, v in u.__dict__.items() if not k.startswith('_')})

Ответ 29

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))

Эта функция может помочь. Я не могу найти лучшего решения для решения проблемы, когда имя атрибута отличается от имени столбца.

Ответ 30

Он понадобится вам везде в вашем проекте, я ответил, что @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" будет там.