处理表单之间的数据
如果我有一个注册流程,总共有3个步骤,那就需要用到3个表单。
就像这样,给大家演示一下:
@app.route('/form/step1', methods=['GET', 'POST'])
def form_step1():
form = form_step_1(request.form)
...validate()...
return render_template('register.html', form=form)
@app.route('/form/step2', methods=['GET', 'POST'])
def form_step2():
form = form_step_2(request.form)
...validate()...
return render_template('register.html', form=form)
@app.route('/form/step3', methods=['GET', 'POST'])
def form_step3():
form = form_step_3(request.form)
...validate()...
return render_template('register.html', form=form)
那么,在这三个步骤之间,处理数据的正确方法是什么呢?所有的数据应该在第三步结束时保存到数据库里。但是如果用户在表单之间想要返回,之前的表单应该重新填充上之前输入的内容。
为了这个目的使用会话(sessions)似乎不是个好主意。
2 个回答
0
如果你不担心你的表单数据被恶意篡改,可以在第二步和第三步的页面中使用隐藏的表单字段来传递数据。可以这样理解……
forms.py
# override EACH form's init to change the widget for each field to a hidden widget if is_hidden kwarg passed.
class form_step_1(forms.Form):
def __init__(self, *args, **kwargs):
is_hidden = kwargs.pop('is_hidden', None)
super(FormName, self).__init__(*args, **kwargs)
if is_hidden:
for field in self.fields:
self.fields[field].widget = forms.HiddenInput()
# Be sure to do this for each form with hidden input needed
views.py
@app.route('/form/step1', methods=['GET', 'POST'])
def form_step1():
form1 = form_step_1(request.POST)
...validate()...
return render_template('register.html', {'form':form1})
@app.route('/form/step2', methods=['GET', 'POST'])
def form_step2():
form1 = form_step_1(request.POST, is_hidden=True)
hidden_forms =[form1]
form2 = form_step_2(request.POST)
...validate()...
return render_template('register.html', {'form':form2, 'hidden_forms':hidden_forms})
@app.route('/form/step3', methods=['GET', 'POST'])
def form_step3():
form1 = form_step_1(request.POST, is_hidden=True)
form2 = form_step_2(request.POST, is_hidden=True)
hidden_forms =[form1, form2]
form = form_step_3(request.form)
...validate()...
if form.is_valid():
# do stuff, save to DB
form1.save()
form2.save()
form3.save()
return HttpReturnRedirect('/success_page/') # Always Redirect after posting form
# if not valid, show again.
return render_template('register.html', {'form':form, 'hidden_forms':hidden_forms })
template.html (assuming you are using a single template for each page
<form action="." etc>
{% csrf_token %}
{{ form }}
{% for each_form in hidden_forms %}
{{ each_form }}
<!-- your submit button -->
</form>
现在,当你的表单在第三步进行提交时,如果数据有效,之前步骤中的每个表单数据都会被保留下来。
如果你想要一个比较冒险的解决方案(这需要多花点功夫),可以看看Django FormWizard。
4
我个人建议使用会话对象来在不同的表单之间传递数据。如果你要传递的数据量不大,可以直接使用Flask自带的cookie功能。否则,你可以重写默认的会话对象,使用Redis在服务器端存储会话数据。这样,你就可以使用会话对象,而不必担心把大量数据存储在cookie里带来的问题。 这意味着你可以这样做:
@app.route('/form/step1', methods=['GET', 'POST'])
def form_step1():
form1 = form_step_1(request.POST)
user_id = current_user.user_id # If you're using flask-login
...validate()...
# dictionary that holds form1, form2, etch
form_data = {"form1": form1, "form2": None, "Form3"=None}
flask.session[user_id] = form_data
redirct_to(url_for("form_step2"))
return render_template('register.html', {'form':form1})
@app.route('/form/step2', methods=['GET', 'POST'])
def form_step2():
form1 = session[user_id][form1]
# A simpler way than passing the whole form is just the data
# you want but for this answer I'm just specifying the whole form.
form = form_step_2(form1)
user_id = current_user.user_id # If you're using flask-login
...validate()...
# dictionary that holds form1, form2, etch
flask.session[user_id]["form2"] = form2
redirct_to(url_for("form_step3"))
return render_template('register.html', form=form)