SQLAlchemy объект ассоциации обновления отношения многие ко многим с дополнительным столбцом - PullRequest
1 голос
/ 31 мая 2019

В моем приложении с набором ' ' может быть связано количество продуктов .Продукты, перечисленные против набора, должны иметь определенные количества.Для этого отношения «многие ко многим» я следовал документации SQLAlchemy , чтобы использовать таблицу связей с дополнительным столбцом (количеством).

Я пытаюсь создать форму, в которой пользователь можетназначить продукты и количества по данному набору.Наборы и продукты уже существуют в базе данных.Данные из формы:

  • set.id
  • product.id
  • количество

Это работает для создания новогосвязь (например, набор 1 «связан» с продуктом 3 с количеством = XYZ), но я получаю ошибку целостности, когда пытаюсь обновить существующую запись.

Я могу вручную добавить отношение / запись (фиктивные данные)или в функции просмотра 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()

Однако, когда я использую код из первого блока вместо(с целью обновления поля 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).

Любопытно, что если я использую form.popluate_obj(set) в своей функции просмотра Flask для обработки данных формы, как описано в моем вопросе здесь , я могу обновлять поля, но не создавать новые «ассоциации».К сожалению, я не знаю, что там происходит за кулисами ...

Мои модели определены так:

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")

Редактировать: I 'мы также попытались отменить операцию, как предложено здесь :

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)]

1 Ответ

2 голосов
/ 01 июня 2019

Вы получаете ошибку целостности, потому что вы пытаетесь создать новый объект с теми же первичными ключами.

Это:

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()

Кроме того, из документации рекомендуется использовать не модель, а реальную таблицу.

...