При использовании wtforms и sqlalchemy форма с отношениями родитель-потомок добавляет новые дочерние элементы в базу данных вместо обновления существующих дочерних элементов. - PullRequest
0 голосов
/ 03 февраля 2020

В простом приложении Flask -SQLAlchemy, использующем WTForms, у меня есть отношение один ко многим, смоделированное с родительской таблицей и дочерней таблицей. Форма, которая обновляет родительский и дочерний элементы по умолчанию, просто добавляет новых дочерних элементов в базу данных, а не обновляет существующие дочерние элементы. В качестве обходного пути / kludge, и, как я покажу в приведенном ниже коде, при обновлении я сначала удаляю всех потомков родителя, а затем добавляю потомков обратно, когда они возвращаются в запросе из формы. Но, конечно же, у WTForms есть способ справиться с этим более элегантно? Мой репозиторий (если вы хотите запустить код) находится здесь: https://github.com/lfernandez55/3200_wtf_parent_child_example. Вот форма:

<form action="{{ url_for('register') }}" method="post" id="parentForm">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name }}

    {{ form.add_child }}

    {% for childform in form.children %}

        {% for field in childform %}
            {{ field.label }} {{ field }}   
        {% endfor %}

    {% endfor %}

    {{ form.submit }}
</form>

А вот и приложение (обновление и ключ находятся в представлении update_registration:

from flask import Flask, render_template, flash, redirect, url_for
from flask_sqlalchemy import SQLAlchemy

from flask_wtf import FlaskForm #Form is deprecated, use FlaskForm instead
from wtforms import StringField, IntegerField, ValidationError, FieldList, FormField, SubmitField, HiddenField, SelectMultipleField, widgets
from wtforms.validators import InputRequired

app = Flask(__name__)
app.config.from_pyfile('config.cfg')
db = SQLAlchemy(app)


# Define the Role data-model
class Child(db.Model):
    __tablename__ = 'child'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(50) )
    age = db.Column(db.Integer())
    parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))

class Parent(db.Model):
    __tablename__ = 'parent'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(50) )
    children = db.relationship("Child", backref='parent', cascade='all')

# Define the Flask forms
# https://stackoverflow.com/questions/49066046/append-entry-to-fieldlist-with-flask-wtforms-using-ajax
class ChildForm(FlaskForm):

    name = StringField(label='Name child')
    age = IntegerField(label='Age child')

    class Meta:
        # No need for csrf token in this child form
        csrf = False

class ParentForm(FlaskForm):

    name = StringField(label='Name parent')
    children = FieldList(FormField(ChildForm), label='Children')
    add_child = SubmitField(label='Add child')

    submit = SubmitField()


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=4000, debug=True)


@app.route('/update_registration', methods=['GET', 'POST'])
def update_registration():
    parentObj = Parent.query.filter(Parent.id == 1).first()
    form = ParentForm(id=parentObj.id, name=parentObj.name, children=parentObj.children)

    if form.add_child.data:
        form.children.append_entry()
        return render_template('update_registration.html', form=form)
    if form.validate_on_submit():
        parentObj.name=form.name.data
        # There should be a way to update the existing children objects rather than deleting and re-adding them
        # But in the below we delete and re-add.  Otherwise updated children simply append to existing children list
        for i in range(len(parentObj.children)):
            db.session.delete(parentObj.children[i])
        for child in form.children.data:
            childObj = Child(name=child['name'],age=child['age'])
            parentObj.children.append(childObj)
        db.session.add(parentObj)
        db.session.commit()
        flash('Parent [and children] Updated!!')
        return redirect(url_for('home_page'))
    return render_template('update_registration.html', form=form)

© 2020 GitHub, In c.

...