Использование WTForms populate_obj для обновления таблицы связей «многие ко многим» с дополнительным столбцом - PullRequest
0 голосов
/ 27 мая 2019

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

С помощью приведенного ниже кода я могу успешно обновлять существующие (введенные вручную) данные в моих таблицах, используя форму, созданную с помощью Flask-WTF, но я не могу добавить новую «связь». Я получаю следующую ошибку:

TypeError: populate_obj: cannot find a value to populate from the 
provided obj or input data/defaults

Я подозреваю, это потому, что python не может найти / не имеет значения для set_id. Когда я print(form.data), я вижу следующий вывод:

'products': [{'product_id': 1, 'quantity': '105', 'csrf_token': '...'}, {'product_id': 2, 'quantity': '123', 'csrf_token': '...'}, {'product_id': 4, 'quantity': '120', 'csrf_token': '..'}]

Согласны ли вы с тем, что отсутствие ссылки на set.id может быть проблемой? Я попытался включить поле set.id в основной класс формы SetForm(), но это не сработало. Есть ли способ как-то передать это в populate_obj() или я должен делать это «вручную», перебирая данные формы следующим образом?

for item in form.products.entries:
   product = Product.query.filter_by(id=item.data['product_id'])
   set = Set.query.get(id)
   association = Set_Product_Association(set=set, product=product, quantity=data['quantity']
   db.session.add(association)

Вот (надеюсь) соответствующие биты кода:

forms.py

class SetProdForm(FlaskForm):
    product_id = SelectField('Product', coerce=int)
    quantity = TextField()

    def __init__(self, *args, **kwargs):
        super(SetProdForm, self).__init__(*args, **kwargs)
        self.product_id.choices = [(product_id.id, product_id.part_number)
                                 for product_id in Product.query.order_by(Product.part_number).all()]

class SetForm(FlaskForm):
    ...
    products = FieldList(FormField(SetProdForm), min_entries=3)
    submit = SubmitField('Update')

models.py

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

views.py

@main.route('/sets/edit/<int:id>',  methods = ['GET', 'POST'])
@login_required
def editSet(id):
     setToBeEdited = Set.query.get_or_404(id)
     form = SetForm(obj=setToBeEdited)
     if form.validate_on_submit():
        form.populate_obj(setToBeEdited)
        db.session.add(setToBeEdited)
        db.session.commit()
        flash('Set definition has been updated.')
        return redirect(url_for('.sets'))
     return render_template('edit_set.html', form=form)
...