2012-06-05 21 views
7

मैं किसी अन्य तालिका से पॉप्युलेट की गई किसी ऑब्जेक्ट की मैप किए गए विशेषता बनाना चाहता हूं।SQLAlchemy घोषणात्मक संपत्ति शामिल होने से (एकल विशेषता, पूरी वस्तु नहीं)

SQLAlchemy प्रलेखन उदाहरण का उपयोग, मैं एक user_name क्षेत्र पता वर्ग पर मौजूद हैं यह हो सकता है ऐसा है कि करना चाहते हैं दोनों को आसानी से पूछे और आसानी से

उदाहरण के लिए (डेटाबेस के लिए एक दूसरे राउंड ट्रिप के बिना) पहुँचा, मैं और user_nameAddress.query.filter(Address.user_name == 'wcdolphin').first() से क्वेरी करने के लिए और फिल्टर में सक्षम हो भी, सब पता वस्तुओं की user_name विशेषता का उपयोग प्रदर्शन दंड के बिना, और यह ठीक से जारी रहती है लिखता है के रूप में __tablename__

class User(Base): 
    __tablename__ = 'users' 

    id = Column(Integer, primary_key=True) 
    name = Column(String(50)) 
    addresses = relation("Address", backref="user") 

class Address(Base): 
    __tablename__ = 'addresses' 

    id = Column(Integer, primary_key=True) 
    email = Column(String(50)) 
    user_name = Column(Integer, ForeignKey('users.name'))#This line is wrong 
में एक विशेषता की उम्मीद होगी करना चाहते हैं 0

मैं यह कैसे कर सकता हूं?

मुझे दस्तावेज को समझने में अपेक्षाकृत मुश्किल लगता है, क्योंकि यह ज्यादातर उदाहरणों, विशेष रूप से फ्लास्क-स्क्लाक्लेमी उदाहरणों के अनुरूप नहीं लगता है।

+0

वास्तव में क्या गलत है दस्तावेज़ीकरण के साथ? [Sqlalchemy ट्यूटोरियल] (http://docs.sqlalchemy.org/en/rel_0_7/orm/tutorial.html) सामान्य कार्यों के लिए सबकुछ शामिल करता है। और बाकी अवधारणाओं में उन्नत अवधारणाएं पाई जाती हैं। – schlamar

उत्तर

6

आप क्वेरी ऑब्जेक्ट पर join के साथ ऐसा कर सकते हैं, इस विशेषता को सीधे निर्दिष्ट करने की आवश्यकता नहीं है। तो अपने मॉडल लगेगा जैसे:

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

Base = declarative_base() 
engine = create_engine('sqlite:///') 
Session = sessionmaker(bind=engine) 

class User(Base): 
    __tablename__ = 'users' 
    id = Column(Integer, primary_key=True) 
    name = Column(String(50)) 
    addresses = relation("Address", backref="user") 

class Address(Base): 
    __tablename__ = 'addresses' 
    id = Column(Integer, primary_key=True) 
    email = Column(String(50)) 
    user_id = Column(Integer, ForeignKey("users.id")) 


Base.metadata.create_all(engine) 

उपयोगकर्ता नाम को छानने के साथ पतों के बाद एक क्वेरी लगता है:

>>> session = Session() 
>>> session.add(Address(user=User(name='test'))) 
>>> session.query(Address).join(User).filter(User.name == 'test').first() 
<__main__.Address object at 0x02DB3730> 

संपादित: आप सीधे एक पते वस्तु से उपयोगकर्ता का उपयोग कर सकते हैं, वहाँ है सीधे पता वर्ग के लिए एक विशेषता संदर्भित करने के लिए कोई जरूरत नहीं:

>>> a = session.query(Address).join(User).filter(User.name == 'test').first() 
>>> a.user.name 
'test' 
+0

कुछ हद तक सही है, यह मेरा इरादा नहीं है, क्योंकि मैं अपने प्रश्न में वर्णित 'पता' की उपयोगकर्ता_नाम संपत्ति तक नहीं पहुंच सकता। कस्टम PHP/हाथ लिखित ओआरएम में इसे लिखते समय, उपयोगकर्ता से उपयोगकर्ता नाम का चयन करने के लिए एसक्यूएल को सही ढंग से उत्पन्न करने का एक आसान मामला है .__ table__ और विशेषता संग्रहित करें, SQLAlchemy को इस परिदृश्य का समर्थन करना चाहिए? –

+0

@wcdolphin ने उत्तर को अपडेट किया। – schlamar

+0

शानदार, यहां कुंजी जादू है जो तब होता है जब आपने बैकफ्रफ़ बनाया है, यह वास्तव में आईडी को क्वेरी करने के लिए उपयोगकर्ता ऑब्जेक्ट को संबोधित करने के लिए 'जानता है'। –

1

आप वास्तव में के एक एसक्यूएल सक्षम संस्करण के लिए पता करना चाहते हैं स्पष्ट रूप से शामिल होने की आवश्यकता के बिना "User.name", आपको एक सहसंबंधित सबक्वायरी का उपयोग करने की आवश्यकता है। यह सभी मामलों में काम करेगा लेकिन डेटाबेस पक्ष (विशेष रूप से MySQL के साथ) पर अक्षम होगा, इसलिए नियमित रूप से जॉइन का उपयोग करके एसक्यूएल पक्ष पर प्रदर्शन प्रदर्शन संभवतः होता है। कुछ एक्स्पलाइन परीक्षण चलाने से यह विश्लेषण करने में मदद मिल सकती है कि कितना प्रभाव हो सकता है।

एक सहसंबंधित कॉलम_प्रोपर्टी() का एक और उदाहरण http://docs.sqlalchemy.org/en/latest/orm/mapped_sql_expr.html#using-column-property पर है।

"सेट" ईवेंट के लिए, एक सहसंबंधित सबक्वायरी केवल पढ़ने-योग्य विशेषता का प्रतिनिधित्व करता है, लेकिन परिवर्तनों को रोकने और उन्हें मूल उपयोगकर्ता पंक्ति पर लागू करने के लिए एक ईवेंट का उपयोग किया जा सकता है। इस में दो तरीकों का नीचे प्रस्तुत कर रहे हैं, एक नियमित रूप से पहचान मानचित्र यांत्रिकी, जो उपयोगकर्ता पंक्ति का भार नहीं पहले से ही मौजूद है, तो देना पड़ेगा का उपयोग कर, अन्य जो पंक्ति के लिए एक सीधा अद्यतन का उत्सर्जन करता है:

from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base 

Base= declarative_base() 

class User(Base): 
    __tablename__ = 'users' 

    id = Column(Integer, primary_key=True) 
    name = Column(String(50)) 
    addresses = relation("Address", backref="user") 

class Address(Base): 
    __tablename__ = 'addresses' 

    id = Column(Integer, primary_key=True) 
    user_id = Column(Integer, ForeignKey('users.id')) 
    email = Column(String(50)) 

Address.user_name = column_property(select([User.name]).where(User.id==Address.id)) 

from sqlalchemy import event 
@event.listens_for(Address.user_name, "set") 
def _set_address_user_name(target, value, oldvalue, initiator): 
    # use ORM identity map + flush 
    target.user.name = value 

    # use direct UPDATE 
    #object_session(target).query(User).with_parent(target).update({'name':value}) 

e = create_engine("sqlite://", echo=True) 
Base.metadata.create_all(e) 

s = Session(e) 
s.add_all([ 
    User(name='u1', addresses=[Address(email='e1'), Address(email='e2')]) 
]) 
s.commit() 

a1 = s.query(Address).filter(Address.user_name=="u1").first() 
assert a1.user_name == "u1" 

a1.user_name = 'u2' 
s.commit() 

a1 = s.query(Address).filter(Address.user_name=="u2").first() 
assert a1.user_name == "u2" 
+0

क्या इस दृष्टिकोण का उपयोग कर कोई फायदा है?एक मानक पायथन संपत्ति अधिक सरल लगती है (मेरा जवाब देखें)। या मुझे कुछ याद आ रहा है? (इसे 'address.user.name' के रूप में एक्सेस करना आईएमओ सबसे पायथन संस्करण है, हालांकि।) – schlamar

+0

अच्छी तरह से वह शामिल होने के बिना भी इसके साथ पूछताछ करने में सक्षम होना चाहता है()। यह पैटर्न एक था जिसे मैंने एसक्यूएलए के शुरुआती दिनों में बहुत अधिक जोर दिया था, और यदि आपको "कुल गणना" की तरह कुछ चाहिए तो इसकी प्रासंगिकता अभी भी प्रासंगिक है। लेकिन एक संबंधित विशेषता प्राप्त करने के लिए, हाँ इतना नहीं। एसक्यूएलए वास्तव में चाहता है कि आप प्रश्नों की ज्यामिति का जादू करें। – zzzeek