sqlalchemy 행 객체를 python dict로 변환


240

열 이름과 값 쌍을 반복하는 간단한 방법이 있습니까?

내 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
질문의 제목이 질문 자체와 일치하지 않습니다. docs 에 따르면 여러 ORM 엔터티 및 / 또는 열식이 포함 된 Query에서 반환 된 결과 행은이 클래스를 사용하여 행을 반환합니다. 이 클래스 이다 sqlalchemy.util.KeyedTuple행 개체 질문의 제목에서은. 그러나 질문의 ​​쿼리는 모델 (매핑 된) 클래스를 사용하므로 행 객체 유형이 대신 모델 클래스입니다 sqlalchemy.util.KeyedTuple.
Piotr Dobrogost

2
@PiotrDobrogost 질문은 2009 년부터 sqlalchemy 버전 0.5.6을 언급합니다
Anurag Uniyal

답변:


232

__dict__다음과 같이 SQLAlchemy 개체 의 내부 에 액세스 할 수 있습니다.

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

24
이 글에서 가장 좋은 대답은 왜 다른 사람들이 훨씬 더 복잡한 솔루션을 제안하는지 모릅니다.
Dave Rawks 2016 년

92
최소 0.7.9 버전에서는 추가 '_sa_instance_state'필드가 제공됩니다.
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}놓으려는 경우) 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

94

의견에서 @zzzeek에 따라 :

"row"가 ORM 매핑 인스턴스가 아닌 핵심 행 개체라고 가정하면 최신 버전의 SQLAlchemy에 대한 정답입니다.

for row in resultproxy:
    row_as_dict = dict(row)

13
그것은 내가 0.5.6를 사용하고, 'XXX 객체가 반복 가능한 아니다'라고, 나는 session.query (클라스) .filter ()에 의해 얻을 수있는 모든 ().
아 누락 Uniyal

60
"row"가 ORM 매핑 인스턴스가 아닌 핵심 행 개체라고 가정하면 최신 버전의 SQLAlchemy에 대한 정답입니다.
zzzeek

48
또한 zzzeek는 sqlalchemy의 제작자입니다.
chris

1
누구든지 이것에 대해 자세히 설명 할 수 있습니까? 나는 멍청한 놈이다.
lameei

1
코어 행 객체와 ORM 매핑 인스턴스의 차이점은 무엇입니까? 의 행에서 작동하지 않습니다 query(MyModel).all(): MyModel 객체는 반복 할 수 없습니다.
Jonathan Hartley

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.


@ DukeDougal 나는 이것이 v0.8 (검사 시스템이 추가되었을 때)에서 작동한다고 생각합니다.
RazerM

1
이것은 Sqlalchemy v2.0에서 작동합니다. 다른 답변은 그렇지 않습니다.
탄 응 우옌

이것은 지연된 열을 고려하지 않습니다
Mark

1
@Mark 기본적으로 제외되어야한다는 것은 분명하지 않습니다. 그럼에도 불구하고, 키가 들어 있지 않은지 확인할 수 있습니다sqlalchemy.inspect(obj).unloaded
RazerM

5
@NguyenThanh SQLAlchemy v2.0 작업은 존재하지 않는 점에서 특히 인상적입니다! 최신 (베타) 릴리스는 v1.3.0b1입니다.
Mark Amery

39

행에는 _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'}

비공개로되어 있으며 향후 버전에서 제거 / 변경 될 수 없습니다.
balki

2
@balki 그것은 잘 문서화 되어 있으며 그렇게 사적인 것은 아닙니다. 주요 밑줄은 일반적으로 파이썬에서 그 의미를 갖지만, 가능한 튜플 키와 충돌하지 않기 위해 사용됩니다.
Ilja Everilä

5
이것은 KeyedTuple에서만 작동하며, 행의 특정 필드를 쿼리 할 때만 반환됩니다. .query (Topic.name)은 KeyedTuple을 반환하지만 .query (Topic)는 ._asdict ()-Derp가없는 Topic을 반환합니다. STB가 아래 답변을 보았습니다.
Chad Lowe

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
실제로, 모든 경우에 대한 더 나은 솔루션은 stackoverflow.com/a/27948279/1023033
TaiwanGrapefruitTea

이것을 시도하면 ResultProxy 객체에 '_asdict'속성이 없습니다.
slashdottir

@ slashdottir, 쿼리 객체를 실행하고 .first()있습니까 (메서드 호출 )?
Sam Bourne

1
이 답변은 잘못된 가정을합니다. 열 이름이 속성 이름과 반드시 ​​일치 할 필요는 없습니다 – RazerM의 답변을 참조하십시오.
Piotr Dobrogost

18

오래된 질문이지만 이것이 구글에서 "sqlalchemy row to dict"에 대한 첫 번째 결과이기 때문에 더 나은 답변을 얻을 가치가 있습니다.

SqlAlchemy가 반환하는 RowProxy 개체에는 items () 메서드가 있습니다. http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

단순히 (키, 값) 튜플 목록을 반환합니다. 따라서 다음을 사용하여 행을 dict로 변환 할 수 있습니다.

파이썬 <= 2.6에서 :

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

파이썬> = 2.7에서 :

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

13
당신은 할 수있다list_of_dicts = [dict(row.items()) for row in rows]
마르쿠스 Meskanen

하나의 걸림돌은 SQLAlchemy가 결과 집합에서 사용하는 열 이름이 table_name_column_name다른 이름을 원할 경우 (예 : just column_name) .label메소드를 사용한다는 것입니다. session.query( MyTable.column_name.label('column_name'), ... )
Aneel

안녕 나는 나를 datetime.datetime (2018, 11, 24, 18, 52, 50)을하지 JSON의 직렬화 * *이 문제의 PLS 도움을 얻고있다
Saravanan Nandhan

13

다음 함수가 다음에 추가된다고 가정하면 class User모든 열의 모든 키-값 쌍을 반환합니다.

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

다른 답변과 달리 객체의 Column클래스 수준에있는 속성 인 객체의 속성 만 반환 됩니다. 따라서 SQLalchemy 또는 _sa_instance_state다른 속성이 없거나 개체에 추가 한 속성 이 포함됩니다. 참고

편집 : 이것은 또한 상속 된 열에서도 작동한다는 것을 잊어 버렸습니다.

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또한 Tipphybrid_methodAssociationProxy 도 포함 시키려면 리턴 합니다.

다른 답변에 대한 비고

속성 을 기반으로 한 모든 답변 (예 : 1 , 2 )은 __dict__단순히 객체의 모든 속성을 반환합니다. 이것은 당신이 원하는 훨씬 더 많은 속성이 될 수 있습니다. 슬프게도 여기에는 _sa_instance_state이 객체에 정의한 다른 속성 이 포함됩니다 .

함수를 기반으로하는 모든 답변 (예 : 1 , 2 ) 은 질문에서 와 같이 작업하도록 정의한 클래스 가 아닌 반환 된 SQLalchemy 행 객체 dict()에서만 작동합니다 .session.execute()class User

해결의 답 에 근거 row.__table__.columns은 확실히 하지 작동합니다. row.__table__.columnsSQL 데이터베이스의 열 이름을 포함합니다. 이들은 python 객체의 속성 이름과 같을 수 있습니다 . 그렇지 않으면을 얻습니다 AttributeError. 답변 내용 (같은 1 , 2 페이지) 기반 class_mapper(obj.__class__).mapped_table.c이 동일하다.


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과 mapping_table의 차이점을 알고 있어야합니다. 예를 들어, db (tbl_employees> tbl_managers, tbl_employees> tbl_staff)에 일종의 테이블 상속을 적용하면 매핑 된 클래스가이를 반영해야합니다 (Manager (Employee), Staff (Employee)). Maps_table.c는 기본 테이블과 상속 테이블의 열 이름을 제공합니다. local_table은 (상속되는) 테이블의 이름 만 제공합니다.
Michael Ekoka

이것은 버전 0.8 이상에서 '_sa_instance_state'필드를 제공하지 않습니다.
Evan Siroky

4
이 답변은 잘못된 가정을합니다. 열 이름이 속성 이름과 반드시 ​​일치 할 필요는 없습니다.
RazerM

11

@balki 답변에 이어 SQLAlchemy 0.8부터 KeyedTuple 객체에 사용 가능한 _asdict ()를 사용할 수 있습니다. 이것은 원래 질문에 대한 간단한 답변을 제공합니다. 이 예제에서 마지막 두 줄 (for 루프)을 예제에서 변경하십시오.

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

위 코드에서 u는 KeyedTuple 클래스의 객체이기 때문에 작동합니다. .all ()은 KeyedTuple의 목록을 반환하기 때문입니다. 따라서 _asdict () 메소드가 있으며 u를 사전으로 반환합니다.

@STB의 대답 : AFAIK, .all ()이 반환하는 anithong은 KeypedTuple의 목록입니다. 따라서 위의 내용은 Query 개체에 적용된 .all () 결과를 처리하는 한 열을 지정하거나 지정하지 않은 경우 작동합니다.


6
이것은 과거에는 사실 일 수 있었지만 SQLAlchemy v1.0 .all()에서는 User인스턴스 목록을 반환 하므로 작동하지 않습니다.
RazerM

@RazerM, 죄송 합니다만, 무슨 뜻인지 이해가되지 않습니다. for 루프는 User 인스턴스 목록을 정확하게 반복하여 (u)를 사전으로 변환 한 다음 인쇄합니다.
jgbarah

3
User인스턴스에는 _asdict메소드 가 없습니다 . 참조 gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8d
RazerM

2
이제 알았습니다. 감사. KeyedTuple 대신 이제 .all ()은 User 객체를 반환합니다. 따라서 v1.0의 문제는 User 객체에서 사전을 얻는 방법입니다. 설명해 주셔서 감사합니다.
jgbarah

10

반복하는 표현식은 행이 아닌 모델 객체 목록으로 평가됩니다 . 따라서 다음은 올바른 사용법입니다.

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

그것들을 dicts로 변환해야합니까? 물론 많은 방법이 있지만 SQLAlchemy의 ORM 부분은 필요하지 않습니다.

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

업데이트 : sqlalchemy.orm.attributes모듈을 살펴보십시오 . 객체 상태와 함께 작동하는 함수 집합이 있으며 특히 유용합니다 instance_dict().


2
다른 코드에는 dict로 데이터가 필요하기 때문에 dict로 변환하고 싶습니다. 모델 객체에 어떤 열이 있는지 알 수 없기 때문에 일반적인 방법을 원합니다
Anurag Uniyal

그리고 내가 그들에 대한 핸들을 얻을 때 나는
model.execute

8

Alex Brasetvik의 답변을 참조하십시오. 한 줄의 코드를 사용하여 문제를 해결할 수 있습니다

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

Alex Brasetvik의 답변의 의견 섹션에서 SQLAlchemy의 작성자 인 zzzeek는 이것이 문제의 "올바른 방법"이라고 말했습니다.


1
@Greenonline 물론, 승인 의견은 Alex Brasetvik의 답변 아래 있습니다. 그의 답변에 대한 링크를 추가하도록 편집
NorWay

무엇입니까 resultproxy?
lameei

8

이런 식으로 시도 할 수 있습니다.

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

쿼리 개체의 내장 개체를 사용하여 쿼리 개체의 dictonary 개체를 반환합니다.

참조 : https://docs.sqlalchemy.org/en/latest/orm/query.html


1
아마도 더 설명이 필요하십니까?
Tiw

1
더 이상 설명 할 것이 없습니다. 결과 객체에 내장 된 메소드입니다. 따라서 모든 결과 또는 단일 행에 대해이 작업을 수행하든 _asdict()기본적으로 필드 이름으로 필드 이름을 압축하고 결과를 사전으로 반환 하는 기본 제공 방법이 있습니다.
Matthew

매우 간결하고 나는 그것이 작동하지만, 할 u내 경우에는 문자열입니다, 나는 모델 _asdict'` @hllau 나를 위해 일한 아래 '개체가 어떤 속성이 없습니다'``오류
티끌 Zart

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

1
또는, 당신이 선호하는 경우 ... : [DICT (우편 (i.keys (), i.values ())) B의 난에 대한]
슬픈 Mychot

이것이 실제로 작동하는 유일한 구문입니다! 나는 한 시간 이상 물건을 노력하고 있습니다.
slashdottir

핵심 선택의 경우 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())

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

다음은 Elixir가 수행하는 방법입니다. 이 솔루션의 가치는 관계의 사전 표현을 재귀 적으로 포함 할 수 있다는 것입니다.

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

연결이 끊어졌습니다. 다음에는 관련 코드도 여기에 복사하십시오.
거스 E

다음에하겠습니다. 올바르게 기억하면 기능이 상당히 길었습니다.
argentpepper

2

이 코드를 사용하면 쿼리 "filter"또는 "join"에이 작업을 추가 할 수도 있습니다.

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("_")])

작동합니다.


1
열 이름이 "_"로 시작하면 어떻게됩니까?
Anurag Uniyal

4
열 이름을 밑줄로 표시해서는 안된다고 생각합니다. 그렇게하면 작동하지 않습니다. 당신이 알고있는 것이 홀수 인 경우, 해당 열을 추가하도록 수정할 수 있습니다.
Singletoned

1

Marco Mariani의 답변에 변형이있어 장식 자로 표현되었습니다. 가장 큰 차이점은 엔티티 목록 을 처리 하고 다른 유형의 반환 값을 안전하게 무시한다는 것입니다 (모의를 사용하여 테스트를 작성할 때 매우 유용합니다).

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

'with_relationships'의 기본값이 false로 변경되면이 값을 재귀 호출로 전달하는 것이 좋습니다. 즉 : d[relationship.key] = to_dict(val,with_relationships) if val else None
니콜라스 해밀턴

address_id 열을 기반으로 사용자와 주소 테이블을 조인하고 사용자 테이블의 모든 열과 주소 테이블의 id 열 만 가져 오려면 결과를 어떻게 얻을 수 있습니까?
Sudhakar

1

python 3.8 이상을 사용하면 데이터 클래스와 함께 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.


Python3.7에서 "NameError : name 'asdict'is not defined"
devnull

내 잘못이야! 파이썬 3.8에 추가 된 기능입니다. 내 대답을 수정했습니다.
toaruScar

그래서 pythonic. 3.8 최고입니다. 그러나 실제로 init 메소드가 필요 하지 않습니까? 선언적 및 데이터 클래스는 모두 일반적인 초기화 메소드를 제공합니다.
Jeff Laughlin

0

나는 새로 유인 된 파이썬 프로그래머이며 Joined 테이블을 사용하여 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)

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을 모두 얻을 수 있습니다.

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

이 클래스의 내용을 .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'}

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"은 필드 이름이 "email"이지만 column.name은 이전과 같이 잘 작동하지 않습니다.

sqlalchemy_base_model.py

또한 나는 여기에 답을 쓴다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.