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

241

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

Моя версия sqlalchemy 0.5.6

Вот пример кода, в котором я пытался использовать dict (row), но он выдает исключение, TypeError: объект 'User' не повторяется

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
Анураг Униял
источник
3
Название вопроса не соответствует самому вопросу. Согласно документам строки результата, возвращаемые Query, которые содержат несколько объектов ORM и / или выражений столбцов, используют этот класс для возврата строк. где этот класс является , sqlalchemy.util.KeyedTupleкоторый является объектом строки из названия вопроса. Однако запрос в вопросе использует класс модели (сопоставленный), поэтому тип объекта строки является классом модели, а не sqlalchemy.util.KeyedTuple.
Петр Доброгост,
2
@PiotrDobrogost Вопрос от 2009 года и упоминает sqlalchemy версию 0.5.6
Anurag Uniyal

Ответы:

233

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

for u in session.query(User).all():
    print u.__dict__
hllau
источник
24
Лучший ответ в этой теме, не знаю, почему все остальные предлагают гораздо более сложные решения.
Дейв Рокс
92
Это дает дополнительное поле '_sa_instance_state', по крайней мере, в версии 0.7.9.
elbear
21
так что это было бы лучше:dictret = dict(row.__dict__); dictret.pop('_sa_instance_state', None)
lyfing
6
это кажется не идеальным, поскольку, как указали люди, __dict__включает в себя _sa_instance_stateзапись, которая должна быть удалена. Если вы обновитесь до будущей версии и добавите другие атрибуты, вам, возможно, придется вернуться назад и вручную обработать их. если вы хотите просто данные столбца (например, взять список экземпляров из запроса и {col.name: getattr(self, col.name) for col in self.__table__.columns}поместить их в фрейм данных pandas), тогда ответ от Anurag Uniyal (с важными исправлениями из комментариев к этому ответу) кажется более кратким и ошибочным. доказательство.
kilgoretrout
14
Этот ответ неверен. Вопрос даже имеет dict(u)и правильно утверждает, что он бросает TypeError.
RazerM
146

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

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}
Анураг Униял
источник
17
Более кратко return dict((col, getattr(row, col)) for col in row.__table__.columns.keys()).
argentpepper
4
@argentpepper да, вы можете даже row2dict = lambda row: dict((col, getattr(row, col)) for col in row.__table__.columns.keys())сделать его реальным, но я предпочитаю, чтобы мой код был читаемым, горизонтально коротким, вертикально длинным
Anurag Uniyal
14
Что если мой столбец не назначен атрибуту с тем же именем? IE, x = Column('y', Integer, primary_key=True)? Ни одно из этих решений не работает в этом случае.
Buttons840
13
drdaeman прав, вот правильный фрагмент:return {c.name: getattr(self, c.name) for c in self.__table__.columns}
charlax
5
Этот ответ делает неверное предположение: имена столбцов не обязательно совпадают с именами атрибутов.
RazerM
95

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

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

for row in resultproxy:
    row_as_dict = dict(row)
Алекс Брасетвик
источник
13
Там написано: «XXX объект не повторяется», я использую 0.5.6, получаю с помощью session.query (Klass) .filter (). All ()
Anurag Uniyal
60
обратите внимание, что это правильный ответ для современных версий SQLAlchemy, если предположить, что «строка» - это основной объект строки, а не экземпляр, сопоставленный с ORM.
zzzeek
48
Также обратите внимание, что zzzeek является создателем sqlalchemy.
Крис
1
Кто-нибудь может уточнить это? Я нуб и не понимаю.
Lameei
1
В чем разница между основным объектом строки и экземпляром, сопоставленным с ORM? Это не работает для меня в строках из query(MyModel).all(): MyModel объект не повторяется.
Джонатан Хартли
81

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

RazerM
источник
@ DukeDougal Я думаю, что это работает с v0.8 (когда была добавлена ​​система контроля).
RazerM
1
Это работает с Sqlalchemy v2.0. Других ответов нет.
Тхань Нгуен
Это не принимает во внимание отложенные столбцы
Mark
1
@ Марк Мне не ясно, что они должны быть исключены по умолчанию. Тем не менее, вы можете проверить, что ключи не находятся вsqlalchemy.inspect(obj).unloaded
RazerM
5
@NguyenThanh Работа с SQLAlchemy v2.0 особенно впечатляет, учитывая его отсутствие! Последняя (бета) версия v1.3.0b1.
Марк Амери
39

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

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'}
Балки
источник
Предполагается, что он является частным и не может быть удален / изменен в будущих версиях.
балки
2
@balki Это довольно хорошо задокументировано и как таковое не совсем личное. Несмотря на то, что в Python это значение имеет главное подчеркивание, здесь оно, вероятно, используется, чтобы не конфликтовать с возможными ключами кортежей.
Илья Эверила
5
Это работает только с KeyedTuple, которые возвращаются только при запросе определенных полей строки. т.е. .query (Topic.name) возвращает KeyedTuple, в то время как .query (Topic) возвращает Topic, которая не имеет ._asdict () - Derp. только что видел ответ СТБ ниже.
Чад Лоу
20

как упомянул @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'}
Сэм Борн
источник
Если атрибуты класса python ORM имеют разные имена из столбцов базы данных, попробуйте следующее решение: stackoverflow.com/questions/27947294/…
TaiwanGrapefruitTea
2
на самом деле, лучшее решение для всех случаев предоставлено автором
sqlalchemy по
Когда я пытаюсь это сделать, я получаю ResultProxy объект не имеет атрибута _asdict
slashdottir
@slashdottir, вы выполняете объект запроса (вызывая .first()метод)?
Сэм Борн
1
Этот ответ делает неверное предположение: имена столбцов не обязательно совпадают с именами атрибутов - см. Ответ RazerM.
Петр Доброгост
18

Старый вопрос, но так как это первый результат для "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]
fgasparini
источник
13
Вы можете просто сделатьlist_of_dicts = [dict(row.items()) for row in rows]
Маркус Месканен
Одна загвоздка в том, что имена столбцов, которые SQLAlchemy использует в результирующем наборе table_name_column_name, если вы хотите использовать разные имена (например, просто column_name), используют .labelметод. session.query( MyTable.column_name.label('column_name'), ... )
Aneel
Привет, я получаю эту проблему, пожалуйста, помогите мне * datetime.datetime (2018, 11, 24, 18, 52, 50) не
поддерживает
13

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

F.Raab
источник
12
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)
Марко Мариани
источник
4
Помните о разнице между local_table и mapped_table. Например, если вы применяете какое-то наследование таблиц в своей базе данных (tbl_employees> tbl_managers, tbl_employees> tbl_staff), ваши сопоставленные классы должны будут отражать это (Manager (Employee), Staff (Employee)). mapped_table.c выдаст вам имена столбцов как базовой таблицы, так и таблицы наследования. local_table дает только имя вашей (наследуемой) таблицы.
Майкл Экока
Это позволяет избежать указания поля '_sa_instance_state', по крайней мере, в версии 0.8+.
Эван Сироки
4
Этот ответ делает неверное предположение: имена столбцов не обязательно совпадают с именами атрибутов.
RazerM
11

После ответа @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.

jgbarah
источник
6
Возможно, это было правдой в прошлом, но в SQLAlchemy v1.0 .all()возвращает список Userэкземпляров, так что это не работает.
RazerM
@ RazerM, извините, но я не понимаю, что вы имеете в виду. Цикл for должен точно выполнять цикл по списку пользовательских экземпляров, преобразовывая их (u) в словари, а затем печатая их ...
jgbarah
3
Userэкземпляры не имеют _asdictметода. См. Gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8d
RazerM
2
Теперь я понял. Спасибо. Вместо KeyedTuple теперь .all () возвращает объекты пользователя. Таким образом, проблема для v1.0 (и выше, я полагаю) состоит в том, как получить словарь из объекта User. Спасибо за разъяснения.
Джгбара
10

Выражение, через которое вы перебираете, оценивает список объектов модели , а не строк. Таким образом, следующее правильное использование их:

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

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

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

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

Денис Откидач
источник
2
Я хочу преобразовать их в dict, потому что для некоторого другого кода нужны данные как dict, и я хочу общий способ, потому что я не буду знать, какие столбцы есть у модели объекта
Anurag Uniyal
и когда я понимаю их, у меня есть доступ только к модельным объектам, поэтому я не могу использовать session.execute и т. д.
Anurag Uniyal
8

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

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

В разделе комментариев Ответа Алексея Брасетвика, zzzeek, ​​создатель SQLAlchemy, заявил, что это «правильный метод» для решения проблемы.

Норвегия
источник
1
@Greenonline Конечно, комментарий одобрения находится под ответом Алекса Брасетвика. Отредактировано для добавления ссылки на его ответ
NorWay
Что это resultproxy?
Lameei
8

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

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

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

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

Эмануэль Медина
источник
1
Добавить еще несколько объяснений, может быть?
Tiw
1
Больше нечего объяснять. Это встроенный метод для объекта результата. Независимо от того, делаете ли вы это для всех результатов или для одной строки, есть встроенный _asdict()метод, который, по сути, объединяет имена полей со значениями полей и возвращает результат в виде словаря.
Мэтью
Очень лаконично, и я бы хотел, чтобы это работало, но uв моем случае это строка, и я получаю сообщение об ошибке: `` Модель 'не имеет атрибута "_asdict'` @hllau ниже сработало для меня
Mote
7

Я нашел этот пост, потому что искал способ преобразовать строку 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()))
Mychot грустный
источник
1
или, если вы предпочитаете ..: [dict (zip (i.keys (), i.values ​​())) для i in b]
Mychot sad
Это единственный синтаксис, который я нашел, который действительно работает! Я пробовал вещи больше часа.
Слэшдоттир
Для выбора ядра RowProxy( cв этом ответе) придерживается протокола отображения, так что вы можете просто позвонить dict(c).
RazerM
4

Вы можете преобразовать объект 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)
Чираг Вора
источник
3

Два пути:

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())
FrostSigh
источник
3

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

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

def query():
    data = session.query(Table).all()
    return to_array(data)
желто-святой
источник
2

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

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
argentpepper
источник
Ссылка мертва. В следующий раз, пожалуйста, скопируйте соответствующий код здесь.
Гас Э
Сделаем в следующий раз. Если я правильно помню, функция была довольно длинной.
argentpepper
2

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

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]
Якир Цубери
источник
1
class User(object):
    def to_dict(self):
        return dict([(k, getattr(self, k)) for k in self.__dict__.keys() if not k.startswith("_")])

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

Singletoned
источник
1
что произойдет, если имя столбца начинается с "_"?
Anurag Uniyal
4
Я полагаю, что вы действительно не должны называть свои столбцы с подчеркиванием. Если вы это сделаете, это не будет работать. Если это просто странный случай, о котором вы знаете, вы можете изменить его, добавив эти столбцы.
Singletoned
1

У меня есть вариант ответа Марко Мариани, выраженный в качестве декоратора. Основное отличие состоит в том, что он будет обрабатывать списки сущностей, а также безопасно игнорировать некоторые другие типы возвращаемых значений (что очень полезно при написании тестов с использованием 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
Крис Р
источник
1

Чтобы завершить ответ @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}
nbarraille
источник
если значение по умолчанию для with_relationships изменено на false, лучше передать это значение рекурсивному вызову. то есть: d[relationship.key] = to_dict(val,with_relationships) if val else None
Николас Гамильтон
как мне добиться результата, если я хочу присоединиться к таблице пользователей и адресов на основе столбца address_id и извлечь все столбцы из таблицы пользователей и только столбец идентификаторов из таблицы адресов.
Судхакар
1

В Python 3.8+ мы можем сделать это с помощью dataclass и asdictметода, который идет с ним:

from dataclasses import dataclass, asdict

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import Column, String, Integer, create_engine

Base = declarative_base()
engine = create_engine('sqlite:///:memory:', echo=False)


@dataclass
class User(Base):
    __tablename__ = 'users'

    id: int = Column(Integer, primary_key=True)
    name: str = Column(String)
    email = Column(String)

    def __init__(self, name):
        self.name = name
        self.email = 'hello@example.com'


Base.metadata.create_all(engine)

SessionMaker = sessionmaker(bind=engine)
session = SessionMaker()

user1 = User("anurag")
session.add(user1)
session.commit()

query_result = session.query(User).one()  # type: User
print(f'{query_result.id=:}, {query_result.name=:}, {query_result.email=:}')
# query_result.id=1, query_result.name=anurag, query_result.email=hello@example.com

query_result_dict = asdict(query_result)
print(query_result_dict)
# {'id': 1, 'name': 'anurag'}

Ключ должен использовать @dataclassдекоратор, и аннотировать каждый столбец с его типом ( : strчасть name: str = Column(String)строки).

Также обратите внимание, что, так как emailне аннотирован, он не включен в query_result_dict.

toaruScar
источник
На Python3.7 я получаю «NameError: имя 'asdict' не определено»
devnull
Виноват! Это функция, добавленная в Python 3.8. Исправлен мой ответ.
toaruScar
Так питонично. 3.8 это круто. Но вам не нужен метод init, не так ли? декларативный и класс данных предоставляют общие методы init.
Джефф Лафлин
0

Я новичок в программировании на 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)
tknightowl
источник
0

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

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

张小诚
источник
0

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

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

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]
человек
источник
0
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))

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

Александр Немиров
источник
0

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

Яш Покар
источник
-1

В большинстве сценариев имя столбца подходит для них. Но, возможно, вы пишете код следующим образом:

class UserModel(BaseModel):
    user_id = Column("user_id", INT, primary_key=True)
    email = Column("user_email", STRING)

column.name «user_email», в то время как имя поля - «электронная почта», column.name не может работать хорошо, как раньше.

sqlalchemy_base_model.py

также я пишу ответ здесь

kaka_ace
источник