2011-08-04 23 views
6
में joinedload/क्वेरी सक्षम संबंधों के लिए contains_eager (आलसी = 'गतिशील' विकल्प) का उपयोग कैसे करें

मैं निम्नलिखित मॉडल वर्गों SQLAlchemy द्वारा घोषित किया है:SQLAlchemy

class User(Base): 
    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False, unique=True) 
    created_at = Colmn(DateTime, nullable=False, default=func.now()) 

class Post(Base): 
    id = Column(Integer, primary_key=True) 
    user_id = Column(Integer, ForeignKey(User.id), nullable=False) 
    user = relationship(User, backref=backref('posts', lazy='dynamic')) 
    title = Column(String, nullable=False) 
    body = Column(Text, nullable=False) 
    created_at = Colmn(DateTime, nullable=False, default=func.now()) 

जैसा कि मैंने उद्धृत, इन मॉडलों एक रिश्ता है और posts नामक इसके बैकफ्रफ़ को क्वेरी-सक्षम होने के लिए सेट किया गया है (lazy='dynamic' विकल्प के माध्यम से)। क्योंकि कुछ उपयोगकर्ताओं के पास पोस्ट का बड़ा सेट हो सकता है जबकि अधिकांश उपयोगकर्ता नहीं करते हैं।

इन मॉडलों के साथ, मैं User.posts के लिए joinedload कोशिश की, लेकिन मैं त्रुटि का सामना करना पड़ा:

>>> users = session.query(User).options(joinedload(User.posts))[:30] 
Traceback (most recent call last): 
    ... 
InvalidRequestError: 'User.posts' does not support object population - eager loading cannot be applied. 

वहाँ किसी भी तरह से इस स्थिति को हल करने के लिए है?

  • कभी कभी User.posts भारी उपयोगकर्ताओं द्वारा लिखित पदों के बड़े सेट की eagerloading से बचने के लिए कटा हुआ जा सकता है: मैं दो कार्यक्षमताओं दोनों निम्नलिखित की जरूरत है।
  • हालांकि आमतौर पर User.posts 1 + N प्रश्नों का उत्पादन नहीं करना चाहिए।

उत्तर

16

समस्या यह है कि पदों के लिए User पर संपत्ति एक गतिशील संबंध है; यह Query ऑब्जेक्ट वापस करना है। संपत्ति को जानने या सुरक्षित रूप से संवाद करने का कोई तरीका नहीं है, इस बार, सभी संबंधित आइटम पहले ही लोड हो चुके हैं।

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

class User(Base): 
    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False, unique=True) 
    created_at = Colmn(DateTime, nullable=False, default=func.now()) 

class Post(Base): 
    id = Column(Integer, primary_key=True) 
    user_id = Column(Integer, ForeignKey(User.id), nullable=False) 
    user = relationship(User, backref=backref('posts')) 
    title = Column(String, nullable=False) 
    body = Column(Text, nullable=False) 
    created_at = Colmn(DateTime, nullable=False, default=func.now()) 

User.post_query = relationship(Post, lazy="dynamic") 
+0

डिफ़ॉल्ट रूप से मेरे मामले में मैं अपवाद सामान्य आलसी लोडिंग द्वारा 'joinload' बनाना चाहता हूं। क्या यह संभव है? – noisy

+0

@noisy, यह संभव है, लेकिन यह इस सवाल के समान नहीं है। [कृपया एक नया पूछें] (http://stackoverflow.com/questions/ask)। – SingleNegationElimination

+0

ध्यान दें कि यदि आप कई से अधिक विन्यासों में इस तरह के कई रिश्तों का उपयोग करते हैं, तो आपको रिश्तों में से एक को 'passive_deletes = True' के रूप में चिह्नित करने की आवश्यकता है, अन्यथा 'StaleDataError' फेंक दिया गया है क्योंकि ORM आइटम में आइटम को हटाने का प्रयास करता है दोनों रिश्तों के माध्यम से एक ही टेबल। http://stackoverflow.com/a/17242712/1255482 – Josh