अजगर के लिए sqlalchemy पंक्ति वस्तु को परिवर्तित करें तानाशाह


240

क्या कॉलम नाम और मूल्य जोड़े पर पुनरावृति करने का एक सरल तरीका है?

Sqlalchemy का मेरा संस्करण 0.5.6 है

यहां नमूना कोड है जहां मैंने तानाशाही (पंक्ति) का उपयोग करने की कोशिश की है, लेकिन यह अपवाद फेंकता है, टाइपरोर: 'उपयोगकर्ता' ऑब्जेक्ट चलने योग्य नहीं है

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
प्रश्न का शीर्षक स्वयं प्रश्न से मेल नहीं खाता है। डॉक्स के अनुसार क्वेरी द्वारा लौटाए गए परिणाम पंक्तियाँ जिनमें कई ORM इकाइयाँ और / या स्तंभ अभिव्यक्तियाँ हैं, पंक्तियों को वापस करने के लिए इस वर्ग का उपयोग करती हैं। जहां यह वर्ग है sqlalchemy.util.KeyedTupleजो प्रश्न के शीर्षक से पंक्ति वस्तु है। हालाँकि प्रश्न में मॉडल (मैप्ड) वर्ग का उपयोग किया जाता है, इस प्रकार पंक्ति वस्तु का प्रकार इसके बजाय मॉडल वर्ग है sqlalchemy.util.KeyedTuple
पायोत्र डोब्रोगॉस्ट

2
@PiotrDobrogost प्रश्न 2009 से है और इसमें sqlalchemy संस्करण 0.5.6 का उल्लेख है
अनुराग उनियाल

जवाबों:


232

आप __dict__निम्न की तरह SQLAlchemy ऑब्जेक्ट के आंतरिक तक पहुँच सकते हैं ::

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

24
इस धागे में सबसे अच्छा जवाब, पता नहीं क्यों हर कोई और अधिक जटिल समाधान का प्रस्ताव कर रहा है।
डेव रॉक्स

92
यह अतिरिक्त '_sa_instance_state' फ़ील्ड देता है, कम से कम 0.7.9 संस्करण में।
13

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}अनुराग उनियाल द्वारा उत्तर दिया गया (उस उत्तर के लिए टिप्पणियों से महत्वपूर्ण सुधार के साथ) दोनों अधिक उपयुक्त और त्रुटि लगता है- सबूत।
किलगोरट्राउट

14
यह उत्तर गलत है। यहां तक ​​कि सवाल भी है dict(u)और सही ढंग से कहा गया है कि यह एक फेंकता है TypeError
रेज़रएम

146

मुझे अच्छा जवाब नहीं मिला, इसलिए मैं इसका उपयोग करता हूं:

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

    return d

संपादित करें: यदि उपरोक्त फ़ंक्शन बहुत लंबा है और कुछ स्वादों के लिए अनुकूल नहीं है तो यहां एक लाइनर (अजगर 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())
अर्जेण्टैपर

4
@argentpepper हाँ, आप row2dict = lambda row: dict((col, getattr(row, col)) for col in row.__table__.columns.keys())इसे एक वास्तविक एक लाइनर बनाने के लिए भी कर सकते हैं, लेकिन मैं अपने कोड को पठनीय, क्षैतिज रूप से छोटा, लम्बे समय तक पसंद करता हूं
अनुराग उनियाल

14
क्या होगा यदि मेरा कॉलम एक ही नाम की विशेषता को नहीं सौंपा गया है? आईई, x = Column('y', Integer, primary_key=True)? इस मामले में कोई भी समाधान काम नहीं करता है।
बटंस .४०

13
drdaeman सही है, यहाँ सही स्निपेट है:return {c.name: getattr(self, c.name) for c in self.__table__.columns}
charlax

5
यह उत्तर एक अमान्य धारणा बनाता है: स्तंभ नाम आवश्यक रूप से विशेषता नामों से मेल नहीं खाते हैं।
रेज़रएम

94

टिप्पणियों में @zzzeek के अनुसार:

ध्यान दें कि यह SQLAlchemy के आधुनिक संस्करणों के लिए सही उत्तर है, यह मानते हुए कि "पंक्ति" एक कोर पंक्ति वस्तु है, न कि ORM- मैप किया गया उदाहरण।

for row in resultproxy:
    row_as_dict = dict(row)

13
इसे कहते हैं 'XXX वस्तु iterable नहीं है', मैं 0.5.6 का उपयोग कर रहा, मैं session.query (Klass) .filter () द्वारा प्राप्त सभी ()।
अनुराग उनियाल

60
ध्यान दें कि यह SQLAlchemy के आधुनिक संस्करणों के लिए सही उत्तर है, यह मानते हुए कि "पंक्ति" एक कोर पंक्ति वस्तु है, न कि ORM- मैप किया गया उदाहरण।
zzzeek

48
यह भी ध्यान दें कि zzzeek sqlalchemy का निर्माता है।
क्रिस

1
किसी को भी इस पर विस्तृत कर सकते हैं? मैं एक noob हूँ यह नहीं मिलता है।
लंगड़ी

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


@DukeDougal मुझे लगता है कि यह v0.8 से काम करता है (जब निरीक्षण प्रणाली को जोड़ा गया था)।
रेजरएम

1
यह Sqlalchemy v2.0 के साथ काम करता है। अन्य उत्तर नहीं।
थान गुयेन

यह कॉलम को स्थगित नहीं करता है
मार्क

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 यह काफी अच्छी तरह से प्रलेखित है और इस तरह काफी निजी नहीं है। हालांकि एक प्रमुख अंडरस्कोर का अर्थ है कि सामान्य रूप से पायथन में, यहां इसका उपयोग संभवतः ट्यूपॉन कीज़ के साथ संभव नहीं होने के लिए किया जाता है।
इलैजा एवरिल

5
यह केवल KeyedTuple s के साथ काम करता है, जो केवल एक पंक्ति के विशिष्ट क्षेत्रों की क्वेरी करते समय वापस किए जाते हैं। .query (Topic.name) एक KeyedTuple लौटाता है, जबकि .query (विषय) एक विषय देता है, जिसमें ._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'}

अगर अजगर ORM वर्ग की विशेषताओं में डेटाबेस कॉलम से अलग-अलग नाम हैं, तो इस समाधान का प्रयास करें: stackoverflow.com/questions/27947294/…
TaiwanGrapefruitTea

2
वास्तव में, सभी मामलों के लिए एक बेहतर समाधान sqlalchemy लेखक द्वारा stackoverflow.com/a/27948279/1023033
ताइपेग्रेफ्रूटीटेआ

जब मैं यह कोशिश करता हूं तो मुझे ResultProxy ऑब्जेक्ट की कोई विशेषता नहीं है '_sdict'
slashdottir

@slashdottir, क्या आप अपनी क्वेरी ऑब्जेक्ट ( .first()विधि को कॉल कर रहे हैं) निष्पादित कर रहे हैं ?
सैम बोर्न

1
यह उत्तर एक अमान्य धारणा बनाता है: स्तंभ नाम आवश्यक रूप से विशेषता नामों से मेल नहीं खाते - RazerM का उत्तर देखें।
पायोत्र डोब्रोगोस्ट

18

पुराना प्रश्न है, लेकिन चूंकि Google में "sqlalchemy row to dict" का यह पहला परिणाम है, इसलिए यह एक बेहतर उत्तर देने के योग्य है।

रोक्प्रॉक्सी ऑब्जेक्ट जो SqlAlchemy रिटर्न आइटम है () विधि: http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items

यह केवल (कुंजी, मान) टुपल्स की एक सूची देता है। तो निम्न में से किसी एक को तानाशाही में बदल सकते हैं:

पायथन में <= 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]
मार्कस मेस्कैनन

एक रोड़ा यह है कि एक परिणाम सेट में SQLAlchemy का उपयोग करने वाले स्तंभ नाम हैं table_name_column_name, यदि आप अलग-अलग नाम चाहते हैं (उदाहरण के लिए। बस column_name), .labelविधि का उपयोग करें । session.query( MyTable.column_name.label('column_name'), ... )
इल

नमस्ते, मैं इस मुद्दे को प्राप्त कर रहा हूँ pls मेरी मदद करें * datetime.datetime (2018, 11, 24, 18, 52, 50) JSON अनुक्रमिक नहीं है *
सरवनन नंदन

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 या आप ऑब्जेक्ट में शामिल नहीं हैं। संदर्भ

EDIT: कहने के लिए भूल जाओ, कि यह विरासत में मिले कॉलम पर भी काम करता है।

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 भी संकर_मथोड और एसोसिएशनप्रॉक्सी लौटाता है।

अन्य उत्तरों के लिए टिप्पणी

प्रत्येक उत्तर (जैसे 1 , 2 ) जो कि __dict__विशेषता पर आधारित होता है, बस वस्तु के सभी गुणों को लौटाता है। यह और अधिक गुण हो सकता है तो आप चाहते हैं। जैसे मैं दुखी हूं, इसमें शामिल है _sa_instance_stateया कोई अन्य विशेषता जिसे आप इस ऑब्जेक्ट पर परिभाषित करते हैं।

प्रत्येक उत्तर (जैसे 1 , 2 ) जो dict()फ़ंक्शन पर आधारित है, केवल SQLalchemy पंक्ति ऑब्जेक्ट्स पर काम करता है जो आपके द्वारा session.execute()काम करने के लिए परिभाषित वर्गों पर नहीं, जैसे class Userप्रश्न से।

हल जवाब पर आधारित है जो row.__table__.columnsनिश्चित रूप से होगा नहीं काम करते हैं। row.__table__.columnsSQL डेटाबेस के स्तंभ नाम हैं। ये केवल पायथन ऑब्जेक्ट के गुण नाम के बराबर हो सकते हैं । अगर आपको नहीं मिलता है 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 और mapped_table के बीच अंतर के बारे में पता होना। उदाहरण के लिए, यदि आप अपने db (tbl_employees> tbl_employees> tbl_staff) में किसी प्रकार का टेबल इनहेरिटेंस लागू करते हैं, तो आपके मैप किए गए वर्गों को इसे (प्रबंधक (कर्मचारी), कर्मचारी (कर्मचारी) को प्रतिबिंबित करना होगा। mapped_table.c आपको बेस टेबल और इनहेरिटिंग टेबल दोनों का कॉलम नाम देगा। local_table केवल आपको आपकी (विरासत) तालिका का नाम देता है।
माइकल एको

यह '_sa_instance_state' फ़ील्ड देने से बचता है, कम से कम संस्करण 0.8+ में।
इवान सिरोकी

4
यह उत्तर एक अमान्य धारणा बनाता है: स्तंभ नाम आवश्यक रूप से विशेषता नामों से मेल नहीं खाते हैं।
RazerM

11

@Balki उत्तर के बाद , SQLAlchemy 0.8 के बाद से आप KeyasTupular ऑब्जेक्ट के लिए उपलब्ध _asdict () का उपयोग कर सकते हैं। यह मूल प्रश्न का एक बहुत ही सरल उत्तर देता है। बस, अपने उदाहरण में इस एक के लिए अंतिम दो लाइनें (लूप के लिए) बदलें:

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

यह काम करता है क्योंकि उपर्युक्त कोड u में टाइप की की एक वस्तु है KeyedTuple , क्योंकि .all () KeyedTuple की सूची देता है। इसलिए इसमें विधि _asdict () है , जो अच्छी तरह से एक शब्दकोश के रूप में यू देता है।

@STB: AFAIK, कि .all () रिटर्न द्वारा उत्तर का WRT करें KeypedTuple की एक सूची है। इसलिए, उपरोक्त कार्य या तो तब करता है जब आप एक कॉलम निर्दिष्ट करते हैं या नहीं, जब तक कि आप (।) के परिणाम के साथ काम कर रहे हैं जैसा कि क्वेरी ऑब्जेक्ट पर लागू होता है।


6
यह अतीत में सच हो सकता है, लेकिन SQLAlchemy v1.0 पर उदाहरणों .all()की एक सूची देता है User, इसलिए यह काम नहीं करता है।
रेज़रएम

@RazerM, क्षमा करें, लेकिन मुझे समझ नहीं आ रहा है कि आपका क्या मतलब है। लूप के लिए उपयोगकर्ता उदाहरणों की सूची के माध्यम से सटीक रूप से लूप करना चाहिए, उन्हें (यू) को शब्दकोशों में परिवर्तित करना, और फिर उन्हें प्रिंट करना ...
jgbarah

3
Userउदाहरणों में एक _asdictविधि नहीं है । Gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8d
RazerM

2
अब मैं समझ गया। धन्यवाद। KeyedTuple के बजाय, अब .all () उपयोगकर्ता ऑब्जेक्ट लौटाता है। तो v1.0 (और ऊपर, मुझे लगता है) के लिए समस्या यह है कि एक उपयोगकर्ता वस्तु से एक शब्दकोश कैसे प्राप्त किया जाए। स्पष्टीकरण के लिए धन्यवाद।
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
मैं उन्हें तानाशाही में बदलना चाहता हूं, क्योंकि कुछ अन्य कोड को तानाशाह के रूप में डेटा की आवश्यकता होती है, और मैं एक सामान्य तरीका चाहता हूं क्योंकि मुझे नहीं पता होगा कि एक मॉडल ऑब्जेक्ट में कौन से कॉलम हैं
अनुराग उनियाल

और जब मैं उन्हें संभालता हूं तो मेरे पास मॉडल ऑब्जेक्ट्स तक पहुंच होती है, इसलिए मैं session.execute आदि का उपयोग नहीं कर सकता हूं
अनुराग उनियाल

8

एलेक्स ब्रासेटविक के उत्तर का संदर्भ लें , आप समस्या को हल करने के लिए कोड की एक पंक्ति का उपयोग कर सकते हैं

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

एलेक्स ब्रासेटविक के उत्तर के टिप्पणी अनुभाग के तहत, SQLAlchemy के निर्माता ने कहा कि यह समस्या के लिए "सही तरीका" है।


1
@Greenonline ज़रूर, अनुमोदन टिप्पणी एलेक्स Brasetvik के जवाब के तहत है। उनके जवाब के लिए जोड़ा लिंक करने के लिए संपादित
NorWay

क्या है resultproxy?
लंगड़ी

8

आप इसे इस तरह से करने की कोशिश कर सकते हैं।

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

यह क्वेरी ऑब्जेक्ट में एक अंतर्निहित पद्धति का उपयोग करता है जो क्वेरी ऑब्जेक्ट की एक तानाशाही वस्तु को लौटाता है।

संदर्भ: https://docs.sqlalchemy.org/en/latest/orm/query.html


1
हो सकता है कि कुछ और समझाएं?
तिवारी

1
वास्तव में समझाने के लिए और कुछ नहीं। यह परिणाम वस्तु पर निर्मित विधि है। तो चाहे आप सभी परिणामों के लिए ऐसा करें, या एक पंक्ति में, एक अंतर्निहित _asdict()पद्धति है जो अनिवार्य रूप से फ़ील्ड नामों को फ़ील्ड मानों के साथ ज़िपित करती है और परिणाम को एक शब्दकोश के रूप में वापस करती है।
मत्ती

बहुत संक्षिप्त और मेरी इच्छा है कि यह काम किया है, लेकिन uमेरे मामले में एक स्ट्रिंग है, और मुझे त्रुटि मिलती है `` मॉडल 'ऑब्जेक्ट में कोई विशेषता नहीं है' _asdict'` @hllau नीचे मेरे लिए काम किया
Mote Zart

7

मुझे यह पद इसलिए मिला है क्योंकि मैं SQLAlchemy पंक्ति को एक तानाशाही में बदलने का तरीका ढूंढ रहा था। मैं SqlSoup का उपयोग कर रहा हूं ... लेकिन इसका उत्तर मेरे द्वारा बनाया गया था, इसलिए, अगर यह किसी को यहां मेरे दो सेंट में मदद कर सकता है:

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

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

1
या, यदि आप पसंद करते हैं ..: [बी में मैं के लिए [ताना (ज़िप (i.keys (), i.values ​​()))
Mychot उदास

यह एकमात्र वाक्यविन्यास है जो मैंने पाया है कि वास्तव में काम करता है! मैं एक घंटे से अधिक समय से कोशिश कर रहा हूं।
स्लैशडॉटिर

कोर चयन के लिए, RowProxy( cइस उत्तर में) मैपिंग प्रोटोकॉल का पालन करता है, इसलिए आप बस कॉल कर सकते हैं dict(c)
रेजरम

4

आप sqlalchemy ऑब्जेक्ट को इस तरह से शब्दकोश में परिवर्तित कर सकते हैं और इसे json / शब्दकोश के रूप में वापस कर सकते हैं।

सहायक कार्य:

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

यहाँ है कि कैसे अमृत करता है। इस समाधान का मूल्य यह है कि यह संबंधों के शब्दकोश प्रतिनिधित्व सहित पुनरावृत्ति की अनुमति देता है।

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

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

वह काम करना चाहिए।


1
यदि स्तंभ नाम "_" से शुरू होता है तो क्या होगा?
अनुराग उनियाल

4
मुझे लगता है कि आप वास्तव में एक प्रमुख अंडरस्कोर के साथ अपने कॉलम का नाम नहीं होना चाहिए। यदि आप करते हैं, यह काम नहीं करेगा। यदि यह सिर्फ एक विषम है, जिसके बारे में आप जानते हैं, तो आप उन स्तंभों को जोड़ने के लिए इसे संशोधित कर सकते हैं।
सिंगलटन

1

डेकोरेटर के रूप में व्यक्त मार्को मारियानी के जवाब पर मेरी भिन्नता है। मुख्य अंतर यह है कि यह संस्थाओं की सूचियों को संभालने के साथ-साथ सुरक्षित रूप से कुछ अन्य प्रकार के रिटर्न मानों (जो मोक्स का उपयोग करके परीक्षण लिखते समय बहुत उपयोगी होता है) को अनदेखा कर रहा है:

@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

@ अनुराग उनियाल के उत्तर को पूरा करने के लिए, यहाँ एक विधि है जो रिश्तों का पुन: अनुसरण करेगी:

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' के लिए डिफॉल्ट को गलत में बदल दिया जाता है, तो इस मान को पुनरावर्ती कॉल के माध्यम से पास करें। यानी: d[relationship.key] = to_dict(val,with_relationships) if val else None
निकोलस हैमिल्टन

मैं परिणाम कैसे प्राप्त कर सकता हूं, अगर मुझे पता_id कॉलम के आधार पर उपयोगकर्ता और पता तालिका में शामिल होना है और उपयोगकर्ता तालिका से सभी कॉलम प्राप्त करना है और पता तालिका से केवल आईडी कॉलम जोड़ना है।
सुधाकर

1

अजगर 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' परिभाषित नहीं किया गया है"
devnull

मेरी गलती! यह अजगर 3.8 में जोड़ा गया एक फ़ंक्शन है। मेरा जवाब तय कर दिया।
toaruScar

तो अजगर। 3.8 का कमाल है। लेकिन आपको वास्तव में init विधि की आवश्यकता नहीं है ? घोषणात्मक और डेटाक्लास दोनों सामान्य init विधियाँ प्रदान करते हैं।
जेफ लाफलिन

0

मैं एक नवनिर्मित पाइथन प्रोग्रामर हूं और जॉन्स में शामिल तालिकाओं के साथ होने वाली समस्याओं में भाग गया। यहां जवाबों की जानकारी का उपयोग करते हुए मैंने JSON को उचित परिणाम वापस करने के लिए एक फ़ंक्शन बनाया, जहां तालिका के नाम को उपनाम में शामिल करने से बचना है, या फ़ील्ड टकराना है।

बस सत्र क्वेरी का परिणाम पास करें:

परीक्षण = सत्र ()। क्वेरी (VMInfo, ग्राहक) .join (ग्राहक) .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}

यदि आप इस तरीके का उपयोग करते हैं, तो आप संशोधित कर सकते हैं_ और 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)

कॉलम .name "user_email" जबकि फ़ील्ड का नाम "ईमेल" है, कॉलम .name पहले की तरह अच्छी तरह से काम नहीं कर सका।

sqlalchemy_base_model.py

मैं भी यहाँ जवाब लिखता हूँ

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.