Как использовать populate_obj в Flask / WTForms с FormField?
У меня есть пользователь с местоположением. Так же, как подтверждение концепции, Location - это FormField в CombinedForm, который должен храниться как пользовательская модель. В конце концов я хочу иметь достаточно большое количество вложенных форм, поэтому мне бы очень хотелось, чтобы form.populate_obj(Model) позаботился об обработке данных. Тем не менее, я должен делать что-то не так. Вот мой код:
# - - - Models - - -
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer(), primary_key=True)
username = db.Column(db.String(40))
location = db.relationship('Location', backref='user')
class Location(db.Model):
__tablename__ = 'locations'
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('users.id'))
descr = db.Column(db.String(50))
# - - - Forms - - -
class LocationForm(NoCsrfForm):
descr = StringField('Location Name')
class CombinedForm(Form):
username = StringField('User', validators=[DataRequired()])
location = FormField(LocationForm) # , default=lambda: Location())
submit = SubmitField('Submit')
# - - - Routes - - -
@app.route('/', methods=['GET', 'POST'])
def index():
user = User(username="not in db")
form = CombinedForm(obj=user)
if form.validate_on_submit():
form.populate_obj(user)
db.session.add(user)
db.session.commit()
return render_template('multi.html', form=form)
Когда я добавлю user.location = [Location(descr="Test")]
к функции индекса я могу сделать поле с помощью {{ form.location }}
на мой взгляд, но изменения в поле формы не влияют на модель, так как populate_obj не заполняет объект Location данными POST. Когда FormField находится внутри FieldList, его заполнение работает.
Что мне не хватает?
Я не смог найти работающий пример FormField без FieldList.
Я потратил много времени на это, даже сделал пример, когда мне показалось, что я понял это, но я ошибался, по крайней мере, когда использовал FormField с populate_list без FieldList. Если есть лучший подход к обработке данных из 2-3 моделей в одной форме, пожалуйста, дайте мне знать. Я схожу с ума, поэтому я был бы очень признателен за помощь. Спасибо за ваше время.
1 ответ
Кажется, я действительно запутался в голове и неправильно понял отношения. Пример ниже работает.
Обратите внимание, что если вы передаете объект, например, экземпляр пользователя, в форму, то уже должно быть заполнено местоположение. Если вы передадите пользователя без местоположения, populate_obj не сможет найти новое местоположение из формы при отправке.
Есть ли способ обойти это?
Это должно работать как подтверждение концепции FormField:
# - - - Models - - -
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer(), primary_key=True)
username = db.Column(db.String(40))
location_id = db.Column(db.Integer, db.ForeignKey('locations.id'))
class Location(db.Model):
__tablename__ = 'locations'
id = db.Column(db.Integer(), primary_key=True)
descr = db.Column(db.String(50))
users = db.relationship('User', backref='location')
# - - - Forms - - -
class LocationForm(NoCsrfForm):
descr = StringField('Location Name')
class CombinedForm(Form):
username = StringField('User', validators=[DataRequired()])
location = FormField(LocationForm, default=lambda: Location())
submit = SubmitField('Submit')
# - - - Routes - - -
@app.route('/', methods=['GET', 'POST'])
def index():
user = User(username="Def")
form = CombinedForm() # don't put a user obj in unless it has a location!
if form.validate_on_submit():
form.populate_obj(user)
db.session.add(user)
db.session.commit()
return render_template('multi.html', form=form)