如何在带有 FormField 的 Flask / WTForms 中使用 populate_obj?

Posted

技术标签:

【中文标题】如何在带有 FormField 的 Flask / WTForms 中使用 populate_obj?【英文标题】:How to use populate_obj in Flask / WTForms with a FormField? 【发布时间】:2016-04-12 17:52:35 【问题描述】:

我有一个有位置的用户。正如概念证明一样,Location 是 CombinedForm 中的一个 FormField,应该存储为 User Model。最终我想要有相当多的嵌套表单,所以我真的希望 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 不会填充带有 POST 数据的位置对象。当 FormField 在 FieldList 中时,填充它就可以了。

我错过了什么?

我无法找到没有 FieldList 的工作 FormField 示例。

我在这方面花了很多时间,甚至在我以为我已经弄明白的时候做了一个example,但我错了,至少在没有 FieldList 的情况下使用 FormField 和 populate_list 时。如果有更好的方法可以在一个表单中处理来自 2-3 个模型的数据,请告诉我。我快疯了,所以我真的很感激一些帮助。感谢您的宝贵时间。

【问题讨论】:

【参考方案1】:

看来我脑子里真的很混乱,搞错了关系。下面的例子有效。

请注意,如果您确实将一个对象(如 User 实例)传递给表单,则它必须已经填充了该位置。如果您传递没有位置的用户,则 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)

【讨论】:

以上是关于如何在带有 FormField 的 Flask / WTForms 中使用 populate_obj?的主要内容,如果未能解决你的问题,请参考以下文章

用数据填充 WTForms FormField FieldList 会在字段中生成 HTML

如何在 ModelAdmin.formfield_for_manytomany() 中使用 Django QuerySet.union()?

如何压缩整个文件夹(带有子文件夹)并通过 Flask 提供它而不将任何内容保存到磁盘

在 ModelForms 中继承 formfield_callback 的 Django 问题

在 ModelForms 中继承 formfield_callback 的 Django 问题

Sharepoint FormField 默认值?