В простом приложении 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.