WTForms做更新时的一些注意点

因为做“新增”和“更新”操作时的内容都是类似的,所以可以定义一个FlaskForm类然后在“新增”和“更新”模板中都使用该类进行渲染:

MovieForm(FlaskForm):

class MovieForm(FlaskForm):

    tag_list = Tag.query.all()

    title = StringField(
        validators=[DataRequired('请输入片名')],
        render_kw={
            'class': "form-control",
            'id': "title",
            'placeholder': "请输入片名"
        }

    )

    url = FileField(
        validators=[DataRequired('请选择文件')],
    )

    info = TextAreaField(
        validators=[DataRequired('请输入简介')],
        render_kw={
            'class': "form-control",
            'rows': 10,
            'placeholder':'请输入影片简介'
        }
    )

   
    tag = SelectField(
        label='影片标签',
        validators=[DataRequired('请选择影片标签')],
        coerce=int,
        render_kw={
            'class': "form-control",
        }
    )

   
    submit = SubmitField(
        '确定',
        render_kw={
            'class': "btn btn-primary"
        }
    )

“新增”模板(代码片段):

              <form role="form" method="post" enctype="multipart/form-data">
                    <div class="box-body">
                        <div class="form-group">
                            <label for="title">影片片名</label>
                            {{form.title}}
                        </div>
                        <div class="form-group">
                            <label for="url">影片文件</label>
                            {{form.url}}
                          
                        </div>
                        <div class="form-group">
                            <label for="info">影片介绍</label>
                            {{form.info}}
                        </div>
                        <div class="form-group">
                            <label for="tagid">影片标签</label>
                            {{form.tag}}
                        </div>
                    </div>
                    <div class="box-footer">
                        {{form.csrf_token}}
                        {{form.submit}}
                    </div>
                </form>

“编辑”模板(代码片段):

              <form role="form" method="post" enctype="multipart/form-data">
                    <div class="box-body">
                        <div class="form-group">
                            <label for="title">影片片名</label>
                            {{form.title(value=movie.title)}}
                        </div>
                        <div class="form-group">
                            <label for="url">影片文件</label>
                            {{form.url}}
                        </div>
                        <div class="form-group">
                            <label for="info">影片介绍</label>
                            {{form.info}}
                        </div>
                        <div class="form-group">
                            <label for="tagid">影片标签</label>
                            {{form.tag}}
                        </div>
                    </div>
                    <div class="box-footer">
                        {{form.csrf_token}}
                        {{form.submit}}
                    </div>
                </form>

如果使用同一个MovieForm渲染模板时,会有一个问题,在“新增”模板中影片文件是必须上传的(required),但是在更新的时候,这一项并不应该是必须修改项,所以在做更新时应该去除掉required。

比较有效的方式是,再写一个类继承自MovieForm,然后子类覆盖掉父类的url属性:

EditMovieForm(MovieForm):

class EditMovieForm(MovieForm):
    url = FileField()

渲染“编辑”页面时的form使用EditMovieForm对象

另外在做“更新”提交时,路由中的代码写法也要注意(代码片段):

@admin_blu.route('/movie/edit/<int:id>', methods=['GET','POST'])
@login_required
def movie_edit(id):
    movie = Movie.query.get_or_404(id)
    form = EditMovieForm()
    form.tag.choices = [(x.id, x.name) for x in Tag.query.all()]
    if request.method=='GET':
        form.star.data = movie.star
        form.info.data = movie.info
        form.tag.data = movie.tag_id
    if form.validate_on_submit():
        data = form.data
        movie.tag_id = data['tag']
        movie.info = data['info']
        movie.title = data['title']
        if data['url']:
            file_url = get_name(form.url.data.filename)
            form.url.data.save(join(app.config['UPLOAD_DIR'], file_url))
            movie.url = file_url
        db.session.add(movie)
        db.session.commit()
        flash('更改{}电影成功'.format(movie.title))
        return redirect(url_for('admin.movielist',page=1))
    return render_template('admin/movieedit.html', movie=movie, form=form)

这段代码中有几个需要注意的点:

1. 以GET的方式进入编辑页面,编辑后点击确定按钮以POST的方式提交数据。无论是GET还是POST方式,都会触发movie_edit方法,并且方法都是从第一行开始执行。

2. 无论以哪种方式进行请求都涉及到了tag,tag是SelectField,必须提供choices。而且为了让choices能够及时反应出数据库中tag的变化,因此应该把choices的赋值放到路由中进行,保证每次请求看到的tag内容都是最新的。

3. 以GET和POST发起请求时,都会创建一个EditMovieForm对象。不同的是,GET请求时创建出的form对象是空的,没有任何内容,所以渲染模板时的数据除了以JinJa2的表达式提供外,有些数据需要以form.field.data的形式在路由中手动赋值填充到表单域中。无论以哪种方式,此时form表单中的内容都来自数据库中已保存的那个movie的信息。POST请求时创建出的form对象是有用户在点击“确定”按钮时表格中所填写的最新的数据的,所以绝对不能以form.field.data形式再去赋值了,而是应该用form.field.data中的内容对movie对象的相关属性进行赋值,赋值完毕后,movie对象拿到了表达中用户提交的最新数据,提交到数据库中进行保存完成数据的更新。

猜你喜欢

转载自blog.csdn.net/piglite/article/details/82528286