Flask教程-Flask页面表单
在HTML页面中,我们可以使用表单来获取用户输入的数据。下面是一个典型的表单示例:
<form method="post">
<label for="name">名字</label>
<input type="text" name="name" id="name"><br>
<label for="occupation">职业</label>
<input type="text" name="occupation" id="occupation"><br>
<input type="submit" name="submit" value="登录">
</form>
在这段HTML代码中,我们使用<form>
标签来定义一个表单,并通过method
属性将提交方法设置为POST。<input>
元素用于创建表单字段,其中type
属性指定为"text"表示创建文本输入框,name
属性定义了字段的名称,id
属性指定了对应的标识符,用于与<label>
元素进行关联。最后的<input>
元素类型设置为"submit"表示创建提交按钮。
需要注意以下几点:
<form>
标签的method
属性设置为"post",以便以POST方式提交表单数据。如果不指定,默认为GET方法,这将通过URL提交表单数据,容易导致数据泄露,且不适用于包含大量数据的情况。<input>
元素必须设置name
属性,否则无法提交数据。在服务器端,我们需要使用这个name
属性值来获取相应字段的数据。<label>
元素用于为输入框字段提供标签文字。使用for
属性来关联<input>
元素的id
属性值。
在主页模板中添加了创建新条目的表单后,用户可以在主页上直接填写并提交表单来创建新的条目。
处理表单数据
在处理表单数据的过程中,需要对视图函数进行相应的修改。以下是处理表单数据的示例代码:
from flask import request, url_for, redirect, flash
# ...
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
# 获取表单数据
title = request.form.get('title')
year = request.form.get('year')
# 验证数据
if not title or not year or len(year) != 4 or len(title) > 60:
flash('Invalid input.')
return redirect(url_for('index'))
# 保存表单数据到数据库
movie = Movie(title=title, year=year)
db.session.add(movie)
db.session.commit()
flash('Item created.')
return redirect(url_for('index'))
movies = Movie.query.all()
return render_template('index.html', movies=movies)
在上述代码中,我们使用了request
对象来获取请求数据。request
对象在Flask中被自动创建,用于存储请求相关的信息。通过判断request.method
的值,我们可以确定请求的方法类型。
在处理POST请求时,我们使用request.form.get()
方法获取表单数据。request.form
是一个特殊的字典对象,可以通过表单字段的name
属性值来获取对应的数据。
使用flash()
函数可以在视图函数中传递提示消息。这个函数会将消息存储在Flask提供的session
对象中,以便在模板中获取。需要在应用配置中设置app.config['SECRET_KEY']
来提供会话签名所需的密钥。
在验证数据时,我们检查表单数据是否符合要求,如果不符合,则使用flash()
函数显示错误提示,并使用redirect()
函数将页面重定向回主页。
最后,使用redirect()
函数将页面重定向回主页,使用url_for()
函数生成主页的URL。
请注意,以上示例中的Movie
和db
对象是根据具体的应用程序和数据库设置进行定义的,并不是Flask的内置对象。您需要根据自己的应用程序进行相应的调整和修改。
编辑条目
编辑的实现和创建类似,我们先创建一个用于显示编辑页面和处理编辑表单提交请求的视图函数:
@app.route('/movie/edit/<int:movie_id>', methods=['GET', 'POST'])
def edit(movie_id):
movie = Movie.query.get_or_404(movie_id)
if request.method == 'POST': # 处理编辑表单的提交请求
title = request.form['title']
year = request.form['year']
if not title or not year or len(year) != 4 or len(title) > 60:
flash('Invalid input.')
return redirect(url_for('edit', movie_id=movie_id)) # 重定向回对应的编辑页面
movie.title = title # 更新标题
movie.year = year # 更新年份
db.session.commit() # 提交数据库会话
flash('Item updated.')
return redirect(url_for('index')) # 重定向回主页
return render_template('edit.html', movie=movie) # 传入被编辑的电影记录
这个视图函数的 URL 规则有一些特殊,如果你还有印象的话,我们在第 2 章的《实验时间》部分曾介绍过这种 URL 规则,其中的 <int:movie_id>
部分表示 URL 变量,而 int
则是将变量转换成整型的 URL 变量转换器。在生成这个视图的 URL 时,我们也需要传入对应的变量,比如 url_for('edit', movie_id=2)
会生成 /movie/edit/2
。
movie_id
变量是电影条目记录在数据库中的主键值,这个值用来在视图函数里查询到对应的电影记录。查询的时候,我们使用了 get_or_404()
方法,它会返回对应主键的记录,如果没有找到,则返回 404 错误响应。
为什么要在最后把电影记录传入模板?既然我们要编辑某个条目,那么必然要在输入框里提前把对应的数据放进去,以便于进行更新。在模板里,通过表单 <input>
元素的 value
属性即可将它们提前写到输入框里。完整的编辑页面模板如下所示:
{% extends 'base.html' %}
{% block content %}
<h3>Edit item</h3>
<form method="post">
Name <input type="text" name="title" autocomplete="off" required value="{{ movie.title }}">
Year <input type="text" name="year" autocomplete="off" required value="{{ movie.year }}">
<input class="btn" type="submit" name="submit" value="Update">
</form>
{% endblock %}
最后在主页每一个电影条目右侧都添加一个指向该条目编辑页面的链接
<span class="float-right">
<a class="btn" href="{{ url_for('edit', movie_id=movie.id) }}">Edit</a>
...
</span>
删除条目
因为不涉及数据的传递,删除条目的实现更加简单。首先创建一个视图函数执行删除操作,如下所示:
@app.route('/movie/delete/<int:movie_id>', methods=['POST']) # 限定只接受 POST 请求
def delete(movie_id):
movie = Movie.query.get_or_404(movie_id) # 获取电影记录
db.session.delete(movie) # 删除对应的记录
db.session.commit() # 提交数据库会话
flash('Item deleted.')
return redirect(url_for('index')) # 重定向回主页
为了安全的考虑,我们一般会使用 POST 请求来提交删除请求,也就是使用表单来实现(而不是创建删除链接):
<span class="float-right">
...
<form class="inline-form" method="post" action="{{ url_for('delete', movie_id=movie.id) }}">
<input class="btn" type="submit" name="delete" value="Delete" onclick="return confirm('Are you sure?')">
</form>
...
</span>
为了让表单中的删除按钮和旁边的编辑链接排成一行,我们为表单元素添加了下面的 CSS 定义:
.inline-form {
display: inline;
}