sqlalchemy: एक क्वेरी द्वारा कई तालिकाओं को कैसे जोड़ा जाए?


92

मेरे पास निम्न SQLAlchemy मैप की गई कक्षाएं हैं:

class User(Base):
    __tablename__ = 'users'
    email = Column(String, primary_key=True)
    name = Column(String)

class Document(Base):
    __tablename__ = "documents"
    name = Column(String, primary_key=True)
    author = Column(String, ForeignKey("users.email"))

class DocumentsPermissions(Base):
    __tablename__ = "documents_permissions"
    readAllowed = Column(Boolean)
    writeAllowed = Column(Boolean)

    document = Column(String, ForeignKey("documents.name"))

मुझे इसके लिए एक तालिका प्राप्त करने की आवश्यकता है user.email = "user@email.com":

email | name | document_name | document_readAllowed | document_writeAllowed

SQLAlchemy के लिए एक क्वेरी अनुरोध का उपयोग करके इसे कैसे बनाया जा सकता है? नीचे दिया गया कोड मेरे लिए काम नहीं करता है:

result = session.query(User, Document, DocumentPermission).filter_by(email = "user@email.com").all()

धन्यवाद,


मैंने पाया है कि निम्नलिखित दो तालिकाओं में शामिल होने के लिए काम करता है: result = session.query(User, Document).select_from(join(User, Document)).filter(User.email=='user@email.com').all()लेकिन मैं अभी तक यह प्रबंधित नहीं कर पाया हूं कि तीन तालिकाओं के लिए समान काम कैसे किया जा सकता है (डॉक्यूमेंटर्स को शामिल करने के लिए)। कोई उपाय?
बाराकिनिन

जब मैं समान कार्य करता हूं, तो मुझे SyntaxError मिलता है: कीवर्ड
इशान तोमर

जवाबों:


91

इसे इस्तेमाल करे

q = Session.query(
         User, Document, DocumentPermissions,
    ).filter(
         User.email == Document.author,
    ).filter(
         Document.name == DocumentPermissions.document,
    ).filter(
        User.email == 'someemail',
    ).all()

6
यह किस तरह का joinकरता है? भीतरी, बाहरी, पार या क्या?
नवाज

7
यह वास्तव में सभी में शामिल नहीं होता है, यह एक टुपल में पंक्ति वस्तुओं को वापस करता है। इस मामले में, इसे वापस चाहते हैं [(<user>, <document>, <documentpermissions>),...]/
नकली नाम

32
"सभी में शामिल नहीं होता है" - यह थोड़ा भ्रामक है। इसमें sql होगा select x from a, b ,cजो एक क्रॉस जॉइन है। फ़िल्टर तब इसे एक आंतरिक जुड़ाव बनाते हैं।
ऐदन केन

7
आप छोड़ कर क्वेरी प्रिंट कर सकते हैं .all()। तो print Session.query....यह देखने के लिए कि यह क्या कर रहा है।
नावक

4
मैं SQLAlchemy में नया हूं। .filter()अगर कॉमा अलग हो जाए तो मुझे कई मापदंड मिल सकते हैं। क्या .filter()कोष्ठक के अंदर अल्पविराम पृथक्करण के साथ एक का उपयोग करना बेहतर है, या .filter()उपरोक्त उत्तर की तरह कई का उपयोग करें ?
इंट्रास्टेलर एक्सप्लोरर

50

एक अच्छी शैली कुछ संबंधों को स्थापित करने और अनुमतियों के लिए एक प्राथमिक कुंजी होगी (वास्तव में, आमतौर पर यह सब कुछ के लिए पूर्णांक प्राथमिक कुंजी सेटअप करने के लिए अच्छी शैली है , लेकिन जो भी हो):

class User(Base):
    __tablename__ = 'users'
    email = Column(String, primary_key=True)
    name = Column(String)

class Document(Base):
    __tablename__ = "documents"
    name = Column(String, primary_key=True)
    author_email = Column(String, ForeignKey("users.email"))
    author = relation(User, backref='documents')

class DocumentsPermissions(Base):
    __tablename__ = "documents_permissions"
    id = Column(Integer, primary_key=True)
    readAllowed = Column(Boolean)
    writeAllowed = Column(Boolean)
    document_name = Column(String, ForeignKey("documents.name"))
    document = relation(Document, backref = 'permissions')

फिर जुड़ाव के साथ एक सरल क्वेरी करें:

query = session.query(User, Document, DocumentsPermissions).join(Document).join(DocumentsPermissions)

queryअंतिम पंक्ति में क्या सेट किया गया है और आप इसमें शामिल हुए रिकॉर्ड तक कैसे पहुँच सकते हैं?
पेट्रिस थेरॉन

@ मुझे यकीन नहीं है कि आपके लिए 'व्हाट्सएप सेट' से क्या मतलब है, लेकिन यह संबंधों और उपज 3-ट्यूपल के अनुसार शामिल हो जाएगा। प्रश्न () कॉल के तर्क अनिवार्य रूप से sqlalchemy में चयनित सूची हैं।
लेटिबी

मैं Document(2 टुपल मान) क्वेरी परिणाम सेट में कैसे पहुंच सकता हूं ?
पेट्रस थेरॉन

1
@PetrusTheron जैसा मैंने कहा, क्वेरी 3-ट्यूपल्स का उत्पादन करेगी। आप तत्वों को इंडेक्स कर सकते हैं, या सिर्फ अनपैक कर सकते हैं:for (user, doc, perm) in query: print "Document: %s" % doc
लेटिबी

1
वाह, अतीत से विस्फोट। 'अनुमतियां' डॉक्यूमेंट ऑब्जेक्ट का एक गुण है, जो आपको डॉक्यूमेंटपर्मिशन ऑब्जेक्ट्स का सेट देता है। इसलिए बैकफुट पर है।
लेटिटबी

37

जैसा कि @letitbee ने कहा, इसका सबसे अच्छा अभ्यास प्राथमिक कुंजियों को तालिकाओं को सौंपना और उचित ORM क्वेरी के लिए अनुमति देने के लिए संबंधों को ठीक से परिभाषित करना है। ऐसा कहे जाने के बाद...

यदि आप निम्नलिखित के साथ एक प्रश्न लिखने में रुचि रखते हैं:

SELECT
    user.email,
    user.name,
    document.name,
    documents_permissions.readAllowed,
    documents_permissions.writeAllowed
FROM
    user, document, documents_permissions
WHERE
    user.email = "user@email.com";

तो आपको कुछ इस तरह से जाना चाहिए:

session.query(
    User, 
    Document, 
    DocumentsPermissions
).filter(
    User.email == Document.author
).filter(
    Document.name == DocumentsPermissions.document
).filter(
    User.email == "user@email.com"
).all()

यदि इसके बजाय, आप कुछ ऐसा करना चाहते हैं:

SELECT 'all the columns'
FROM user
JOIN document ON document.author_id = user.id AND document.author == User.email
JOIN document_permissions ON document_permissions.document_id = document.id AND document_permissions.document = document.name

तो फिर आपको कुछ करना चाहिए:

session.query(
    User
).join(
    Document
).join(
    DocumentsPermissions
).filter(
    User.email == "user@email.com"
).all()

उस बारे में एक नोट ...

query.join(Address, User.id==Address.user_id) # explicit condition
query.join(User.addresses)                    # specify relationship from left to right
query.join(Address, User.addresses)           # same, with explicit target
query.join('addresses')                       # same, using a string

अधिक जानकारी के लिए, डॉक्स पर जाएं ।


4
यह करो। देखें - बहुत कुछ सामानों में निर्दिष्ट नहीं है। ऐसा इसलिए है क्योंकि यदि टेबल / डीबी-मॉडल पहले से ही इन तालिकाओं के बीच उचित विदेशी कुंजी के साथ सेटअप किया गया है - SQLAlchemy आपके लिए उचित कॉलम पर शामिल होने का ख्याल रखेगा।
ब्रैड

8

अब्दुल के जवाब पर विस्तार करते हुए, आप KeyedTupleकॉलम में शामिल होकर पंक्तियों के असतत संग्रह के बजाय प्राप्त कर सकते हैं:

q = Session.query(*User.__table__.columns + Document.__table__.columns).\
        select_from(User).\
        join(Document, User.email == Document.author).\
        filter(User.email == 'someemail').all()

1
यह काम। हालाँकि, ऑब्जेक्ट को क्रमबद्ध करते समय वे स्तंभ नाम गायब हैं।
लुकास

1

यह फ़ंक्शन ट्यूपल्स की सूची के रूप में आवश्यक तालिका का उत्पादन करेगा।

def get_documents_by_user_email(email):
    query = session.query(User.email, User.name, Document.name,
         DocumentsPermissions.readAllowed, DocumentsPermissions.writeAllowed,)
    join_query = query.join(Document).join(DocumentsPermissions)
    return join_query.filter(User.email == email).all()

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