SQLAlchemy отношение «многие ко многим», обновляющее объект ассоциации с дополнительным столбцом

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

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

  • установить идентификатор
  • идантификационный номер продукта
  • количество

Это работает для создания новой ассоциации (например, набор 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")

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

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)
maslak 31.05.2019 10:45

Спасибо за ваше предложение, но, как вы можете видеть в ошибке, на которую я ссылался, она имеет правильные значения, поэтому ваше предложение не имеет никакого значения.

Till 01.06.2019 08:20
Новые приложения с использованием ChatGPT
Новые приложения с использованием ChatGPT
Я собираюсь вернуться к теме, которую уже освещал ранее, - чатгпт.
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Kubernetes - это портативная, расширяемая платформа с открытым исходным кодом для управления контейнерными рабочими нагрузками и сервисами, которая...
Другой маршрут в Flask Python
Другой маршрут в Flask Python
Flask - это фреймворк, который поддерживает веб-приложения. В этой статье я покажу, как мы можем использовать @app .route в flask, чтобы иметь другую...
3
2
2 287
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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()

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

Большое спасибо за вашу помощь и объяснение - очень признателен! Работает и имеет смысл. Что касается использования фактической таблицы вместо модели, для моего варианта использования здесь, где бы вы предложили записать дополнительную информацию (количество), если бы я хотел последовать этому совету?

Till 01.06.2019 15:49

Сохраняйте ту же структуру (набор, продукт и количество), но используйте метод db.Table, а не расширение db.Model. Хороший ответ, почему лучше, можно найти здесь с примерами.

tgdn 01.06.2019 16:00

Спасибо. Совершенно очевидно, что я новичок в этом, поэтому извиняюсь, если не тороплюсь. Причина, по которой я использовал модель над таблицей, заключается в том, что мне нужно хранить дополнительную информацию об отношениях. Информация, на которую вы ссылаетесь, гласит: «Короче говоря, если вам не нужно хранить дополнительные данные об отношениях, просто используйте db.Table, это сэкономит ваше время». Итак, моя проблема в том, что я делать хочу хранить дополнительные данные...

Till 01.06.2019 16:12

Держите модель тогда, это не имеет значения.

tgdn 01.06.2019 16:18

Другие вопросы по теме