【问题标题】:SQLAlchemy Inserting Data in a Many-to-Many Relationship with Association TableSQLAlchemy 在与关联表的多对多关系中插入数据
【发布时间】:2016-04-04 19:07:00
【问题描述】:

我见过一些与此类似的问题,但没有一个是一针见血的。本质上,我在使用 SQLAlchemy 的 Flask 应用程序中拥有三个表模型 Center()Business()CenterBusiness()。目前我正在以这种方式添加到上述关系中:

biz = Business(typId=form.type.data, name=form.name.data,
               contact=form.contact.data, phone=form.phone.data)
db.session.add(biz)
db.session.commit()

assoc = CenterBusiness(bizId=biz.id, cenId=session['center'])
db.session.add(assoc)
db.session.commit()

如您所见,这有点难看,我知道有一种方法可以通过定义的关系一次性完成。我在 SQLAlchemy 的文档上看到他们对使用这样的表进行了解释,但我似乎无法让它工作。

#Directly from SQLAlchemy Docs
p = Parent()
a = Association(extra_data="some data")
a.child = Child()
p.children.append(a)

#My Version Using my Tables
center = Center.query.get(session['center']
assoc = CenterBusiness()
assoc.business = Business(typId=form.type.data, name=form.name.data,
                          contact=form.contact.data, phone=form.phone.data)
center.businesses.append(assoc)
db.session.commit()

不幸的是,这似乎不起作用...任何帮助将不胜感激,我在下面发布了所涉及的模型。

class Center(db.Model):
    id = db.Column(MEDIUMINT(8, unsigned=True), primary_key=True,
                   autoincrement=False)
    phone = db.Column(VARCHAR(10), nullable=False)
    location = db.Column(VARCHAR(255), nullable=False)
    businesses = db.relationship('CenterBusiness', lazy='dynamic')
    employees = db.relationship('CenterEmployee', lazy='dynamic')

class Business(db.Model):
    id = db.Column(MEDIUMINT(8, unsigned=True), primary_key=True,
                   autoincrement=True)
    typId = db.Column(TINYINT(2, unsigned=True),
                      db.ForeignKey('biz_type.id',
                                    onupdate='RESTRICT',
                                    ondelete='RESTRICT'),
                      nullable=False)
    type = db.relationship('BizType', backref='businesses',
                           lazy='subquery')
    name = db.Column(VARCHAR(255), nullable=False)
    contact = db.Column(VARCHAR(255), nullable=False)
    phone = db.Column(VARCHAR(10), nullable=False)
    documents = db.relationship('Document', backref='business',
                                lazy='dynamic')

class CenterBusiness(db.Model):
    cenId = db.Column(MEDIUMINT(8, unsigned=True),
                      db.ForeignKey('center.id',
                                    onupdate='RESTRICT',
                                    ondelete='RESTRICT'),
                      primary_key=True)
    bizId = db.Column(MEDIUMINT(8, unsigned=True),
                      db.ForeignKey('business.id',
                                    onupdate='RESTRICT',
                                    ondelete='RESTRICT'),
                      primary_key=True)
    info = db.relationship('Business', backref='centers',
                           lazy='joined')
    archived = db.Column(TINYINT(1, unsigned=True), nullable=False,
                         server_default='0')

【问题讨论】:

  • 到底发生了什么?有错误吗?数据库的状态不是你期望的那样吗?
  • 当我运行示例中所示的代码并阅读查询时,它似乎正在做大部分应该做的事情。但我从来没有看到插入语句,只是选择然后回滚,没有立即定义的原因。
  • 我不确定它是否相关,但你可以configure the relationships so you don't need to work with the join tables directlychildren = relationship('Child', secondary=association_table)
  • @dirn 这对于多对多来说是完美的,但据我所知,它不包括带有关联对象的真实表。
  • 你是对的。您实际上想要Association Object 部分。 children = relationship('Association', back_populates='parent')

标签: python flask sqlalchemy many-to-many associations


【解决方案1】:

我能够让它工作,我的问题在于以下代码(粗体错误):

#My Version Using my Tables
center = Center.query.get(session['center']
assoc = CenterBusiness()
**assoc.info** = Business(typId=form.type.data, name=form.name.data,
                          contact=form.contact.data, phone=form.phone.data)
center.businesses.append(assoc)
db.session.commit()

正如我在问题中的评论中所解释的那样:

好吧,我的问题是我没有使用关系键“info” 我在我的 CenterBusiness 模型中定义了附加的关联。 我说的是 center.business 认为商业这个词 案件是任意的。但是,我需要实际参考 关系。因此,我已经设置了相应的密钥 CenterBusiness 是信息。

我仍然会接受任何更新和/或更好的方法来处理这种情况,尽管我认为这是当时最好的方法。

【讨论】:

    【解决方案2】:

    下面的例子可以帮助你 更多详情http://docs.sqlalchemy.org/en/latest/orm/extensions/associationproxy.html

    class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(64))
    
         # association proxy of "user_keywords" collection
         # to "keyword" attribute
         keywords = association_proxy('user_keywords', 'keyword')
    
         def __init__(self, name):
             self.name = name
    
    class UserKeyword(Base):
         __tablename__ = 'user_keyword'
         user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
         keyword_id = Column(Integer, ForeignKey('keyword.id'), primary_key=True)
         special_key = Column(String(50))
    
          # bidirectional attribute/collection of "user"/"user_keywords"
          user = relationship(User,
                backref=backref("user_keywords",
                                cascade="all, delete-orphan")
            )
    
        # reference to the "Keyword" object
        keyword = relationship("Keyword")
    
        def __init__(self, keyword=None, user=None, special_key=None):
            self.user = user
            self.keyword = keyword
            self.special_key = special_key
    
    class Keyword(Base):
       __tablename__ = 'keyword'
       id = Column(Integer, primary_key=True)
       keyword = Column('keyword', String(64))
    
      def __init__(self, keyword):
          self.keyword = keyword
    
      def __repr__(self):
           return 'Keyword(%s)' % repr(self.keyword)
    

    【讨论】:

    • 好的,我明白你在说什么......那么使用association_proxyrelationship 有什么好处?您也可以访问其他功能的关联表吗? (即:查询和/或过滤)
    • 它将帮助您进行查询操作。您可以访问关联表的其他属性。
    • 你可以通过关系来做到这一点,我试图更清楚地理解差异?它是否在返回的对象中维护直接键?还是在返回的对象中也作为对象返回?
    猜你喜欢
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 2015-03-29
    • 2018-11-24
    • 2020-03-23
    • 1970-01-01
    相关资源
    最近更新 更多