I have a problem that I'm working on several days.
I have a Flask app and in some place I want to edit some data in my DB. Data model I want to edit is similar to(using Flask-SQLAlchemy):
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(64))
last_name = db.Column(db.String(64))
address = db.relationship('Address', backref='user', lazy='dynamic')
class Address(db.Model):
id = db.Column(db.Integer, primary_key=True)
street = db.Column(db.String(64))
region = db.Column(db.String(64))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
Having defined model, I designed next form:
class AddUser(FlaskForm):
first_name = StringField("first_name", validators=[ InputRequired()])
last_name = StringField("last_name", validators=[ InputRequired()])
region = StringField("region", validators=[ InputRequired()])
In Flask, edit function looks like this:
@app.route('/edit_user/<int:id>', methods=['GET', 'POST'])
def edit_user(id):
qry = User.query.filter_by(id=id).first()
if qry:
form = AddUser(obj=qry)
if request.method == 'POST' and form.validate():
# save edits
qry.first_name = form.first_name .data
qry.last_name = form.last_name.data
qry.address.region = form.region.data
db.session.commit()
flash('Socnet updated successfully!')
return redirect(url_for("view_record", user=form.id.data, level='overview'))
return render_template('add_user.html', form=form, id=id)
else:
return 'Error loading #{id}'.format(id=id)
Unfortunately, the form looks like
First name: My_name
Last name: My_lastname
Region: [<Address 1>]
So it looks like WTForms doesn't know what to do with relationships. If I write the template manually, I will use it like qry.adrress.region
and it would work without any problems, but I really don't want to build the forms by myself.
This case is not unique. The same issues arises with a table autogeneration module.
I know I miss something valuable. Please, help.
as an easy solution, if the user can have only one address, change the relationship to one-to-one or modify your user model to include the address
if you want to use one-to-one: just change the relationship line as follows:
address = db.relationship('Address', backref='user', useList=False)
or one model for both user and address
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(64))
last_name = db.Column(db.String(64))
street = db.Column(db.String(64))
region = db.Column(db.String(64))
then you form will be as follows:
class AddUser(FlaskForm):
first_name = StringField("first_name", validators=[ InputRequired()])
last_name = StringField("last_name", validators=[ InputRequired()])
street = StringField("street", validators=[ InputRequired()])
region = StringField("region", validators=[ InputRequired()])
then flask route
@app.route('/edit_user/<int:id>', methods=['GET', 'POST'])
def edit_user(id):
qry = User.query.filter_by(id=id).first()
if qry:
form = AddUser(obj=qry)
if request.method == 'POST' and form.validate():
# save edits
qry.first_name = form.first_name .data
qry.last_name = form.last_name.data
qry.street = form.street.data
qry.region = form.region.data
db.session.commit()
flash('Socnet updated successfully!')
return redirect(url_for("view_record", user=form.id.data, level='overview'))
return render_template('add_user.html', form=form, id=id)
else:
return 'Error loading #{id}'.format(id=id)