处理表单之间的数据

5 投票
2 回答
2730 浏览
提问于 2025-04-28 02:20

如果我有一个注册流程,总共有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)

撰写回答