मुझे sqlalchemy back_populates का उपयोग कब करना होगा?


84

जब मैं इस गाइड के बाद SQLAlchemy संबंध उदाहरण का प्रयास करता हूं: मूल संबंध पैटर्न

मेरे पास यह कोड है

#!/usr/bin/env python
# encoding: utf-8
from sqlalchemy import create_engine
from sqlalchemy import Table, Column, Integer, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base(bind=engine)

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))
    parent = relationship("Parent")

Base.metadata.create_all()

p = Parent()
session.add(p)
session.commit()
c = Child(parent_id=p.id)
session.add(c)
session.commit()
print "children: {}".format(p.children[0].id)
print "parent: {}".format(c.parent.id)

यह अच्छी तरह से काम करता है, लेकिन गाइड में, यह कहता है कि मॉडल होना चाहिए:

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    **children = relationship("Child", back_populates="parent")**

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))
    **parent = relationship("Parent", back_populates="children")**

मुझे अपने उदाहरण में back_populatesया उसकी आवश्यकता क्यों नहीं है backref? मुझे एक या दूसरे का उपयोग कब करना चाहिए?

जवाबों:


160

यदि आप उपयोग करते backrefहैं तो आपको दूसरी मेज पर संबंध घोषित करने की आवश्यकता नहीं है।

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child", backref="parent")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))

यदि आप उपयोग नहीं कर रहे हैंbackref , और relationshipअलग से परिभाषित कर रहे हैं , तो यदि आप उपयोग नहीं करते हैं back_populates, तो sqlalchemy को रिश्तों को जोड़ना नहीं पता होगा, ताकि एक को संशोधित करने से दूसरे को भी संशोधित किया जा सके।

इसलिए, आपके उदाहरण में, जहां आपने relationshipअलग-अलग परिभाषित किया है , लेकिन एक back_populatesतर्क प्रदान नहीं किया है, एक क्षेत्र को संशोधित करना आपके लेनदेन में अन्य को स्वचालित रूप से अपडेट नहीं करेगा।

>>> parent = Parent()
>>> child = Child()
>>> child.parent = parent
>>> print(parent.children)
[]

देखें कि यह स्वतः childrenफ़ील्ड कैसे नहीं भरता है ?

अब, यदि आप एक back_populatesतर्क देते हैं, तो sqlalchemy खेतों को जोड़ेगा।

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child", back_populates="parent")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))
    parent = relationship("Parent", back_populates="children")

तो अब हम प्राप्त करते हैं

>>> parent = Parent()
>>> child = Child()
>>> child.parent = parent
>>> print(parent.children)
[Child(...)]

Sqlalchemy को पता है कि ये दोनों क्षेत्र अब संबंधित हैं, और एक-दूसरे को अपडेट किए जाने पर अपडेट करेंगे। यह ध्यान देने योग्य है कि उपयोग backrefकरने से यह भी होगा। back_populatesयदि आप हर वर्ग पर संबंधों को परिभाषित करना चाहते हैं, तो उपयोग करना अच्छा है, इसलिए सभी क्षेत्रों को केवल मॉडल वर्ग में देखना आसान है, इसके बजाय अन्य वर्गों को देखने के लिए जो बैकफ़्रे के माध्यम से फ़ील्ड परिभाषित करते हैं।


48
back_populatesबनाम के बारे में एक नोट backref: backrefअधिक रसीला है क्योंकि आपको दोनों वर्गों पर संबंध घोषित करने की आवश्यकता नहीं है, लेकिन व्यवहार में मुझे लगता है कि यह लाइन पर इसे बचाने के लायक नहीं है। मुझे लगता back_populatesहै कि बेहतर है, न केवल इसलिए कि अजगर संस्कृति में "स्पष्ट है निहित से बेहतर है" (पायथन के ज़ेन), लेकिन जब आपके पास कई मॉडल हैं, तो इसकी घोषणा पर एक त्वरित नज़र के साथ आप सभी रिश्तों और उनके नामों को खत्म होने के बजाय देख सकते हैं सभी संबंधित मॉडल। इसके अलावा, इसका एक अच्छा पक्ष back_populatesयह है कि आपको अधिकांश IDE पर दोनों दिशाओं में ऑटो-पूर्ण मिलता है))
Fabiano

बैकफ़ायर को लागू करना आसान लग सकता है (विशेषकर यदि आप स्पष्ट रूप से टिप्पणियों का उपयोग करते हुए दोनों वर्गों में संबंध को इंगित करते हैं, तो कम से कम मैंने ऐसा सोचा था ...), जब तक कि आपको एक टेबल पर कई संबंधों को लागू करने और कंटेनरों के साथ काम करने की आवश्यकता न हो। अंत में back_populates आपके कोड को समझने में आसान बनाता है
Rhdr

क्या parent_idवास्तव में बाल के तहत आवश्यक है? और सहायक तालिकाओं के बारे में क्या, जैसा कि प्रलेखन में
Luiz Tauffer

1
@LuizTauffer parent_idवास्तविक विदेशी कुंजी क्षेत्र है जो माता-पिता के बच्चे के संबंधों को संग्रहीत करता है। यह आवश्यक है। हेल्पर टेबल कई-से-कई रिश्तों को परिभाषित करने के लिए हैं (उदाहरण के लिए, यदि बच्चा एक से अधिक माता-पिता हो सकता है)। ऊपर दिया गया fkey उदाहरण शास्त्रीय वन-टू-मेन उदाहरण है, जहां प्रत्येक बच्चे के एक और केवल एक माता-पिता होते हैं, और एक माता-पिता के कई बच्चे हो सकते हैं।
ब्रेंडन एबेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.