Sqlalchemy satır nesnesini python dict'e dönüştürme


241

Sütun adı ve değer çiftleri üzerinde yineleme yapmanın basit bir yolu var mı?

Benim sqlalchemy versiyonum 0.5.6

Burada dict (satır) kullanarak denedim örnek kodu, ancak istisna atıyor, TypeError: 'Kullanıcı' nesnesi yinelenemez

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)

Bu kodu sistem çıktılarımda çalıştırıyorum:

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
Sorunun başlığı sorunun kendisiyle eşleşmiyor. Göre dokümanlar birden orm varlıkları ve / veya sütun ifadelerini içeren Query tarafından döndürülen satırları Sonuç dönüş satırları bu sınıfın faydalanmak. nerede bu sınıf olduğunu sqlalchemy.util.KeyedTuplehangi satır nesne Sorunun başlığından. Ancak sorudaki sorgu model (mapped) sınıfını kullanır, bu nedenle satır nesnesi türü yerine model sınıfı olur sqlalchemy.util.KeyedTuple.
Piotr Dobrogost

2
@PiotrDobrogost Soru 2009 yılından ve sqlalchemy sürüm 0.5.6 bahseder
Anurag Uniyal

Yanıtlar:


232

__dict__Aşağıdaki gibi bir SQLAlchemy nesnesinin iç kısmına erişebilirsiniz :

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

24
Bu konudaki en iyi cevap, neden herkesin daha karmaşık çözümler önerdiğini bilmiyorum.
Dave Rawks

92
Bu, en azından 0.7.9 sürümünde fazladan bir '_sa_instance_state' alanı verir.
elbear

21
yani bu daha iyi olurdu:dictret = dict(row.__dict__); dictret.pop('_sa_instance_state', None)
8'de lyfing

6
insanlar işaret ettikleri için kaldırılması gereken __dict__bir _sa_instance_stategiriş içerdiğinden bu ideal değildir . gelecekteki bir sürüme yükseltme yaparsanız ve diğer özellikler eklenirse geri dönüp bunlarla manuel olarak ilgilenmeniz gerekebilir. sadece sütun verilerini (örneğin, bir sorgudan örneklerin bir listesini alıp bir panda veri çerçevesinde bırakmak) {col.name: getattr(self, col.name) for col in self.__table__.columns}Anurag Uniyal tarafından yanıtlandığı gibi (yorumlardan bu cevaba yapılan önemli düzeltmelerle) hem daha özlü hem de hata gibi görünür. kanıt.
kilgoretrout

14
Bu cevap yanlış. Soru, dict(u)a attığını bile doğru bir şekilde ifade ediyor TypeError.
RazerM

146

Ben iyi bir cevap alamadım bu yüzden bunu kullanın:

def row2dict(row):
    d = {}
    for column in row.__table__.columns:
        d[column.name] = str(getattr(row, column.name))

    return d

Düzenleme: yukarıdaki işlev çok uzunsa ve bazı tatlar için uygun değilse, burada bir astar (python 2.7+)

row2dict = lambda r: {c.name: str(getattr(r, c.name)) for c in r.__table__.columns}

17
Daha özlü bir şekilde return dict((col, getattr(row, col)) for col in row.__table__.columns.keys()).
argentpepper

4
@argentpepper evet bunu row2dict = lambda row: dict((col, getattr(row, col)) for col in row.__table__.columns.keys())gerçek bir astar yapmak için bile yapabilirsiniz , ancak
kodumun

14
Sütunum aynı adda bir özniteliğe atanmamışsa ne olur? IE, x = Column('y', Integer, primary_key=True)? Bu çözümlerin hiçbiri bu durumda çalışmaz.
Buttons840

13
drdaeman doğru, işte doğru snippet:return {c.name: getattr(self, c.name) for c in self.__table__.columns}
charlax

5
Bu yanıt geçersiz bir varsayım yapar: sütun adları mutlaka özellik adlarıyla eşleşmez.
RazerM

95

Yorumlarda @zzzeek'e göre:

SQLAlchemy'nin modern sürümleri için doğru yanıt olduğunu, "satır" ın ORM eşlemeli bir örnek değil, çekirdek bir satır nesnesi olduğunu varsayalım.

for row in resultproxy:
    row_as_dict = dict(row)

13
'XXX nesnesi yinelenemez' diyor, 0.5.6 kullanıyorum, session.query (Klass) .filter () ile elde ediyorum. All ()
Anurag Uniyal

60
SQLAlchemy'nin modern sürümleri için doğru yanıt olduğunu, "satır" ın ORM eşlemeli bir örnek değil, çekirdek bir satır nesnesi olduğunu varsayalım.
zzzeek

48
Ayrıca zzzeek'in sqlalchemy'nin yaratıcısı olduğunu unutmayın.
chris

1
Herkes bu konuda ayrıntılı bir açıklama yapabilir mi? Ben bir çaylağım ve bunu anlama.
lameei

1
Bir çekirdek satır nesnesi ile ORM eşlemeli bir örnek arasındaki fark nedir? Benim için şu satırlarda işe yaramaz query(MyModel).all(): MyModel nesnesi yinelenemez.
Jonathan Hartley

81

SQLAlchemy v0.8 ve daha yeni sürümlerde denetim sistemini kullanın .

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)

.keyAşağıdaki gibi sütun adından farklı olabilen öznitelik adı olduğuna dikkat edin:

class_ = Column('class', Text)

Bu yöntem de işe yarar column_property.


@DukeDougal Bence bu v0.8'den (denetim sistemi eklendiğinde) çalışıyor.
RazerM

1
Bu, Sqlalchemy v2.0 ile çalışır. Diğer cevaplar yok.
Thanh Nguyen

Bu, ertelenmiş sütunları dikkate almaz
İşareti

1
@Mark Varsayılan olarak hariç tutulmaları gerektiği açık değil. Bununla birlikte, tuşların bulunmadığını kontrol edebilirsinizsqlalchemy.inspect(obj).unloaded
RazerM

5
@NguyenThanh SQLAlchemy v2.0 ile çalışmak, yokluğu nedeniyle özellikle etkileyici! En son (beta) sürüm v1.3.0b1'dir.
Mark Amery

39

satırların _asdict()dikte eden bir işlevi vardır

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

Özel olması gerekiyordu ve gelecekteki sürümlerde kaldırılamaz / değiştirilemez.
balki

2
@balki Oldukça iyi belgelenmiştir ve bu nedenle oldukça özel değildir. Her ne kadar önde gelen bir alt çizgi genel olarak Python'da bu anlama sahip olsa da, muhtemelen olası tuple tuşları ile çatışmamak için kullanılır.
Ilja Everilä

5
Bu yalnızca, yalnızca bir satırın belirli alanlarını sorgularken döndürülen KeyedTuple s ile çalışır. yani .query (Topic.name) bir KeyedTuple döndürürken, .query (Topic) ._asdict () - Derp içermeyen bir Konu döndürür. STB'lerin aşağıda cevap verdiğini gördüm.
Chad Lowe

20

@ balki'nin belirttiği gibi:

_asdict()Bir şekilde döndürülür çünkü belirli bir alanını sorgulama eğer yöntem kullanılabilir KeyedTuple .

In [1]: foo = db.session.query(Topic.name).first()
In [2]: foo._asdict()
Out[2]: {'name': u'blah'}

Ancak, bir sütun belirtmezseniz, diğer önerilen yöntemlerden birini kullanabilirsiniz (örneğin, @charlax tarafından sağlanan yöntem). Bu yöntemin yalnızca 2.7+ için geçerli olduğunu unutmayın.

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 sınıfı özniteliklerinin veritabanı sütunlarından farklı adları varsa, şu çözümü deneyin: stackoverflow.com/questions/27947294/…
TaiwanGrapefruitTea

2
aslında, sqlalchemy yazar tarafından stackoverflow.com/a/27948279/1023033
Taiwan

Bunu denediğimde ResultProxy nesnesi '_asdict' özniteliğine sahip değilim
slashdottir

@slashdottir, sorgu nesnesini çalıştırıyor .first()musunuz ( yöntemi çağırıyor )?
Sam Bourne

1
Bu yanıt geçersiz bir varsayım yapar: sütun adları mutlaka özellik adlarıyla eşleşmez - RazerM'in cevabına bakın.
Piotr Dobrogost

18

Eski soru, ama bu Google'da "sqlalchemy satır dikte" ilk sonuç beri daha iyi bir cevap hak ediyor.

SqlAlchemy'nin döndürdüğü RowProxy nesnesinin items () yöntemi vardır: http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

Sadece (anahtar, değer) gruplarının bir listesini döndürür. Böylece, bir satır aşağıdakileri kullanarak dikteye dönüştürülebilir:

Python <= 2,6'da:

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

Python'da> = 2.7:

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

13
Yapabilirsinizlist_of_dicts = [dict(row.items()) for row in rows]
Markus Meskanen

Bir engel, SQLAlchemy'nin bir sonuç kümesinde kullandığı sütun adlarının table_name_column_namefarklı adlar (örneğin column_name, sadece ) istiyorsanız , .labelyöntemi kullanmasıdır . session.query( MyTable.column_name.label('column_name'), ... )
Aneel

Merhaba ben bu sorunu alıyorum pls bana yardım * datetime.datetime (2018, 11, 24, 18, 52, 50) JSON serileştirilebilir değil
Saravanan Nandhan

13

Aşağıdaki işlevlerin aşağıdakilere ekleneceği varsayılarak class Usertüm sütunların tüm anahtar / değer çiftleri döndürülür:

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

diğer cevaplardan farklı olarak, yalnızca nesnenin Columnsınıf düzeyinde öznitelikleri olan nesnenin öznitelikleri döndürülür . Bu nedenle, SQLalchemy veya nesneye eklediğiniz hiçbir _sa_instance_stateözellik veya başka bir özellik dahil değildir. Referans

EDIT: Bunun miras alınan Sütunlar üzerinde de çalıştığını söylemeyi unutun.

hybrid_propery usantısı

hybrid_propertyNitelikleri de eklemek istiyorsanız aşağıdakiler işe yarar:

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_

Burada, Sütunlara, _gizlemek istediğinizi belirtmek için bir başlıkla işaretlediğinizi varsayalım hybrid_property. Referans

Tipp all_orm_descriptors ayrıca dahil etmek istiyorsanız hybrid_method ve AssociationProxy değerlerini döndürür .

Diğer cevaplara ilişkin açıklamalar

Özniteliğe dayanan her yanıt ( 1 , 2 gibi ) __dict__nesnenin tüm özniteliklerini döndürür. Bu istediğinizden çok daha fazla özellik olabilir. Üzgünüm gibi _sa_instance_statebu nesne veya bu nesne üzerinde tanımladığınız başka bir özellik içerir .

İşlevi temel alan her yanıt ( 1 , 2 gibi ) dict()yalnızca sorudansession.execute() gibi çalışmayı tanımladığınız sınıflar tarafından döndürülmeyen SQLalchemy satır nesneleri üzerinde çalışır class User.

Çözme cevap dayanmaktadır row.__table__.columnskesinlikle olacak değil iş. row.__table__.columnsSQL Veritabanı sütun adlarını içerir. Bunlar yalnızca python nesnesinin nitelik adına eşit olabilir . Değilse bir olsun AttributeError. Buna dayalı cevaplar için ( 1 , 2 gibi ) class_mapper(obj.__class__).mapped_table.caynıdır.


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 ve mapped_table arasındaki farkın farkında olun. Örneğin, db'nize (tbl_employees> tbl_managers, tbl_employees> tbl_staff) bir tür tablo devralması uygularsanız, eşlenen sınıflarınızın bunu (Yönetici (Çalışan), Personel (Çalışan)) yansıtması gerekir. mapped_table.c size hem temel tablonun hem de devralınan tablonun sütun adlarını verecektir. local_table size yalnızca (devralma) tablonuzun adını verir.
Michael Ekoka

Bu, en azından 0.8+ sürümünde '_sa_instance_state' alanı verilmesini önler.
Evan Siroky

4
Bu yanıt geçersiz bir varsayım yapar: sütun adları mutlaka özellik adlarıyla eşleşmez.
RazerM

11

@Balki yanıtını takiben, SQLAlchemy 0.8'den beri KeyedTuple nesneleri için kullanılabilen _asdict () kullanabilirsiniz. Bu, orijinal soruya oldukça basit bir cevap verir. Sadece, örneğinizde bunun için son iki satırı (for döngüsü) değiştirin:

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

Bu, yukarıdaki kodda u KeyedTuple tür sınıfında bir nesne olduğu için çalışır , çünkü .all () bir KeyedTuple listesini döndürür. Bu nedenle , güzel bir sözlük olarak u döndüren _asdict () yöntemine sahiptir .

@STB: AFAIK cevabını YAZIN, .all () ifadesinin döndürdüğü bir anahtarlı anahtar listesi. Bu nedenle, yukarıdaki bir sütun belirtirseniz veya belirtmezseniz, bir Sorgu nesnesine uygulanan .all () sonucunu ele aldığınız sürece çalışır.


6
Bu geçmişte doğru olabilirdi, ancak SQLAlchemy v1.0'da .all()bir Userörnek listesi döndürür , bu yüzden bu işe yaramaz.
RazerM

@ RazerM, üzgünüm, ama ne demek istediğini anlamıyorum. For döngüsü, kullanıcı örnekleri listesinde tam olarak döngü yapmalı, bunları (u) sözlüklere dönüştürmeli ve sonra yazdırmalıdır ...
jgbarah

3
Userörneklerin bir _asdictyöntemi yoktur. Bkz. Gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8d
RazerM

2
Şimdi anladım. Teşekkürler. KeyedTuple yerine, şimdi .all () kullanıcı nesnelerini döndürür. Yani v1.0 (ve yukarı, sanırım) için sorun bir kullanıcı nesnesi dışında bir sözlük almak için nasıl. Açıklama için teşekkürler.
jgbarah

10

Yinelemekte olduğunuz ifade , satırlar yerine model nesneleri listesi olarak değerlendirilir . Yani, bunların doğru kullanımı:

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

Gerçekten onları dikte dönüştürmek gerekiyor mu? Elbette, birçok yol var, ancak SQLAlchemy'nin ORM kısmına ihtiyacınız yok:

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

Güncelleme : sqlalchemy.orm.attributesModüle bir göz atın . Özellikle sizin için yararlı olabilecek nesne durumuyla çalışmak için bir dizi işlevi vardır instance_dict().


2
Bunları dikte etmek için dönüştürmek istiyorum, çünkü diğer bazı kodların dict olarak verilere ihtiyacı var ve genel bir yol istiyorum çünkü bir model nesnesinin hangi sütunlara sahip olduğunu
bilmeyeceğim

ve onları ele aldığımda ben sadece model nesnelerine erişim var, bu yüzden session.execute vb kullanamazsınız
Anurag Uniyal

8

Alex Brasetvik'in Cevabına bakın , sorunu çözmek için bir kod satırı kullanabilirsiniz

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

Alex Brasetvik'in Cevabının yorum bölümünde, SQLAlchemy'nin yaratıcısı zzzeek bunun sorunun "Doğru Yöntemi" olduğunu belirtti.


1
@Greenonline Elbette, onay yorumu Alex Brasetvik'in cevabı altında.
Cevabına

Nedir resultproxy?
lameei

8

Bunu bu şekilde yapmaya çalışabilirsiniz.

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

Sorgu nesnesinin dikte nesnesini döndüren yerleşik bir yöntem kullanır.

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


1
Biraz daha açıklayan ekleyin?
Tiw

1
Açıklamak için gerçekten fazla bir şey yok. Sonuç nesnesi üzerinde yerleşik bir yöntemdir. Bu işlemi tüm sonuçlar için mi yoksa tek bir satır için mi yaparsanız yapın _asdict(), temel olarak alan adlarını alan değerleriyle fermuar haline getiren ve sonucu sözlük olarak döndüren yerleşik bir yöntem vardır.
Matthew

Çok özlü ve çalışmasını diliyorum ama ubenim durumumda bir dize ve `` Model 'nesnesinin hiçbir özelliği yok' _asdict '' @hllau benim için çalıştı
Mote Zart

7

Bu yazıyı buldum çünkü bir SQLAlchemy satırını bir diktüre dönüştürmenin bir yolunu arıyordum. SqlSoup kullanıyorum ... ama cevap kendi başıma oluşturuldu, bu yüzden birine yardımcı olabilirse, iki sentim:

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

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

1
ya da, isterseniz ..: [b için i için [dict (zip (i.keys (), i.values ​​()))]
Mychot sad

Bu gerçekten işe yaradığını bulduğum tek sözdizimi! Bir saatten fazla bir süredir deniyorum.
slashdottir

Çekirdek seçimler için, RowProxy( cbu cevapta) eşleme protokolüne bağlı kalır, böylece arayabilirsiniz dict(c).
RazerM

4

Sqlalchemy nesnesini böyle sözlüğe dönüştürebilir ve json / dictionary olarak döndürebilirsiniz.

Yardımcı fonksiyonlar:

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) 

Sürücü Fonksiyonu:

def all_products():
    all_products = Products.query.all()
    return to_array(all_products)

3

İki yol:

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

Dokümanlar çok basit bir çözüm sunuyor: 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

İksir bunu böyle yapıyor. Bu çözümün değeri, ilişkilerin sözlük temsilini yinelemeli olarak izin vermesidir.

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

Bağlantı öldü. Bir dahaki sefere lütfen ilgili kodu da buraya kopyalayın.
Gus E

Bir dahaki sefere yapacağız. Doğru hatırlarsam, işlev oldukça uzundu.
argentpepper

2

Bu kod ile ayrıca sorgu "filtre" veya "katılmak" ve bu işe eklemek için!

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

Bu işe yaramalı.


1
sütun adı "_" ile başlıyorsa ne olur?
Anurag Uniyal

4
Sütunlarınızı gerçekten alt çizgi ile adlandırmamalısınız. Eğer yaparsan, işe yaramaz. Bildiğiniz tek garip ise, bu sütunları eklemek için değiştirebilirsiniz.
Singletoned

1

Marco Mariani'nin dekoratörü olarak ifade edilen cevabında bir varyasyonum var. Temel fark, varlık listelerini ele almasının yanı sıra diğer bazı dönüş değerleri türlerini de güvenli bir şekilde göz ardı etmesidir (alay kullanarak testler yazarken çok yararlıdır):

@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'un cevabını tamamlamak için, ilişkileri tekrar tekrar takip edecek bir yöntem var:

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' varsayılan değerinin false olarak değiştirilmesi durumunda, bu değeri özyinelemeli çağrıya iletmeniz daha iyi olur. ie: d[relationship.key] = to_dict(val,with_relationships) if val else None
Nicholas Hamilton

adres_id sütununa dayalı kullanıcı ve adres tablosuna katılmak ve kullanıcı tablosundan tüm sütunu ve adres tablosundan yalnızca kimlik sütununu almak istersem sonucu nasıl elde edebilirim.
Sudhakar

1

Python 3.8+ ile bunu dataclass ve asdictonunla birlikte gelen yöntemle yapabiliriz:

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

Anahtar, @dataclassdekoratörü kullanmak ve her sütuna türüyle ( satırın : strparçası name: str = Column(String)) açıklama eklemektir .

Ayrıca email, not eklenmediğinden, içine dahil edilmediğini de unutmayın query_result_dict.


Python3.7 "NameError: name 'asdict' tanımlı değil" olsun
devnull

Benim hatam! Bu, python 3.8'e eklenen bir işlevdir. Cevabım düzeltildi.
toaruScar

Çok pitonik. 3.8 harika. Ama init yöntemine gerçekten ihtiyacınız yok, değil mi? hem bildirim hem de veri sınıfı genel başlatma yöntemleri sağlar.
Jeff Laughlin

0

Ben yeni basmış bir Python programcısı ve birleştirilmiş tablolarla JSON alma sorunları koştu. Buradaki yanıtlardan gelen bilgileri kullanarak, takma adlardan kaçınmak veya alanların çarpışmasını önlemek için tablo adlarının dahil edildiği JSON'a makul sonuçlar döndürmek için bir işlev oluşturdum.

Bir oturum sorgusunun sonucunu iletmeniz yeterlidir:

test = Oturum (). sorgusu (VMInfo, Müşteri) .join (Müşteri) .order_by (VMInfo.vm_name) .limit (50). offset (10)

json = sqlAl2json (test)

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

modelleri tablo sütun mysql sütun eşit değilse.

gibi :

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

Kullanmanız gerekiyor:

 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}

bu şekilde kullanırsanız, change_time ve create_time değerlerini alabilirsiniz.

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

Sınıf Öznitelikleri adı mysql sütun deposuna eşit olmadığından


0

Bu içeriği döndür: sınıf: .KeyedTuplesözlük olarak

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

Herkes ve kendim uğruna, bunu nasıl kullanırım:

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

Bu işlev yardımcı olabilir. Öznitelik adı sütun adlarından farklı olduğunda sorunu çözmek için daha iyi bir çözüm bulamıyorum.


0

Projenizin her yerinde buna ihtiyacınız olacak, ben apriciate @anurag iyi çalışıyor cevap verdi. Bu noktaya kadar onu kullanıyordum, ancak tüm kodunuzu bozacak ve ayrıca varlık değişimi ile çalışmayacak.

Bunun yerine, SQLAlchemy'de temel sorgu sınıfınızı devralın

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)

Bundan sonra nesnenizi "as_dict" yöntemini tanımlayacağınız her yerde orada olacaksınız.


-1

Çoğu senaryoda, sütun adı onlar için uygundur. Ama belki kodu şöyle yazıyorsunuz:

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

alan adı "e-posta" iken column.name "user_email" ise, column.name eskisi kadar iyi çalışmaz.

sqlalchemy_base_model.py

ayrıca cevabı buraya yazıyorum

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.