【问题标题】:SQLAlchemy many-to-many relationship updating association object with extra columnSQLAlchemy 多对多关系更新具有额外列的关联对象
【发布时间】:2019-10-16 17:26:54
【问题描述】:

在我的应用程序中,一个“set”可以有许多与之关联的“products”。针对一组列出的产品必须定义数量。对于这种多对多关系,我遵循SQLAlchemy documentation 使用带有附加列(数量)的关联表。

我正在尝试创建一个表单,用户可以在其中根据给定的集合分配产品和数量。集合和产品都已存在于数据库中。表格中的数据是:

  • set.id
  • product.id
  • 数量

这可以创建一个新的关联(例如,set 1 被“链接”到数量=XYZ 的产品 3)但是当我尝试更新现有记录时出现完整性错误。

我可以手动添加关系/记录(虚拟数据)或在 Flask 视图函数中添加如下:

s = Set.query.get(2)
p = Product.query.get(3)
a = Set_Product_Association(set=s, product=p, quantity=23)
db.session.add(a)
db.session.commit()

手动更新记录(不同数量)如下工作:

s.products[0].quantity = 43
db.session.add(s)
db.session.commit()

但是,当我改用第一个块中的代码时(目的是更新给定的现有集合和产品 ID 的 quantity 字段),即:

a = Set_Product_Association(set=s, product=p, quantity=43)

我收到一个完整性错误

sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: set_product_association.set_id, set_product_association.product_id [SQL: 'INSERT INTO set_product_association (set_id, product_id, quantity) VALUES (?, ?, ?)'] [parameters: (2, 3, 43)]

我假设这是告诉我我正在尝试追加一条新记录,而不是更新现有记录。

我应该如何处理这个问题? “手动”方法有效,但依赖于在列表中计算出正确的索引(即正确的 product.id)。

奇怪的是,如果我在我的 Flask 视图函数中使用form.popluate_obj(set) 来处理我的问题here 中描述的表单数据,我可以更新字段但不能创建新的“关联”。不幸的是,我不知道幕后发生了什么......

我的模型是这样定义的:

class Set_Product_Association(db.Model):
    __tablename__ = 'set_product_association'

    set_id = db.Column(db.Integer, db.ForeignKey('sets.id'), primary_key=True)
    product_id = db.Column(db.Integer, db.ForeignKey('products.id'), primary_key=True)

    quantity = db.Column(db.Integer)

    product = db.relationship("Product", back_populates="sets")
    set = db.relationship("Set", back_populates="products")

class Set(db.Model):
    __tablename__ = 'sets'

    id = db.Column(db.Integer, primary_key=True)
    products = db.relationship("Set_Product_Association", 
                                        back_populates="set")

class Product(db.Model):
    __tablename__= 'products'

    id = db.Column(db.Integer, primary_key=True)
    part_number = db.Column(db.String(100), unique=True, nullable=False)
    sets = db.relationship("Set_Product_Association", 
                                     back_populates="product")

编辑: 我也尝试过按照here的建议撤消操作:

s = Set.query.get(2)
a = Set_Product_Association()
a.quantity = 43
a.product = Product.query.get(3)
a.set = s
db.session.commit()

但我仍然收到错误:

sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: set_product_association.set_id, set_product_association.product_id [SQL: 'INSERT INTO set_product_association (set_id, product_id, quantity) VALUES (?, ?, ?)'] [parameters: (2, 3, 43)]

【问题讨论】:

  • a = Set_Product_Association(set_id=3, product_id=12, quantity=23)
  • 感谢您的建议,但正如您在我引用的错误中看到的那样,它具有正确的值,因此您的建议没有任何区别。

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


【解决方案1】:

您会收到完整性错误,因为您尝试使用相同的主键创建新对象。

这个:

a = Set_Product_Association(set=s, product=p, quantity=43)

不更新,而是创建。

如果要更新表中的实际行,则需要更新现有的:

assoc = Set_Product_Association.query.filter_by(set=s, product=p).first()
assoc.quantity = 43
db.session.commit()

另外,从documentation 开始,建议不要使用模型,而是使用实际表格。

【讨论】:

  • 非常感谢您的帮助和解释 - 非常感谢!有效且非常有意义。关于在模型上使用实际表格,对于我的用例,如果我想遵循该建议,您建议在哪里记录额外信息(数量)?
  • 保持相同的结构(集合、产品和数量),但使用db.Table 方法而不是扩展db.Model。可以在here 中找到关于为什么它更好的一个很好的答案,并附有示例。
  • 谢谢。很明显,我是新手,如果我跟不上的话,我很抱歉。我使用模型而不是表的原因是我需要存储有关关系的其他信息。您链接的信息指出“总之,如果您不需要存储有关关系的额外数据,只需使用db.Table,它将节省您的时间。”所以我的问题是我确实想要存储额外的数据...
  • 那保留模型,没关系。
猜你喜欢
  • 1970-01-01
  • 2015-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-30
  • 2018-11-24
  • 1970-01-01
相关资源
最近更新 更多