Python 处理表单之间的数据

Python 处理表单之间的数据,python,forms,flask,flask-wtforms,Python,Forms,Flask,Flask Wtforms,如果我有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', meth

如果我有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)
在这三个步骤之间处理数据的正确方法是什么?所有数据都应该在步骤3结束时提交到数据库。但是表单之间的back操作应该再次填充上一个表单


为此目的使用会话似乎不好。

如果您没有任何理由担心表单数据被劫持后,可以在第二和第三视图中使用隐藏的表单字段传递数据。按照这些思路思考

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>
forms.py
#覆盖每个表单的init,如果传递了隐藏的kwarg,则将每个字段的小部件更改为隐藏的小部件。
课程表格\u步骤\u 1(forms.form):
定义初始化(self,*args,**kwargs):
is_hidden=kwargs.pop('is_hidden',无)
super(FormName,self)。\uuuuuu init\uuuuuuu(*args,**kwargs)
如果是隐藏的:
对于self.fields中的字段:
self.fields[field].widget=forms.HiddenInput()
#确保对每个需要隐藏输入的表单执行此操作
views.py
@app.route('/form/step1',methods=['GET','POST'])
def form_step1():
form1=form_步骤_1(request.POST)
…验证()。。。
返回呈现模板('register.html',{'form':form1})
@app.route('/form/step2',methods=['GET','POST'])
def form_step2():
form1=form_步骤_1(request.POST,is_hidden=True)
隐藏形式=[form1]
form2=form_step_2(request.POST)
…验证()。。。
返回render_模板('register.html',{'form':form2,'hidden_forms':hidden_forms})
@app.route('/form/step3',methods=['GET','POST'])
def form_step3():
form1=form_步骤_1(request.POST,is_hidden=True)
form2=form_步骤_2(request.POST,is_hidden=True)
隐藏形式=[form1,form2]
form=form\u步骤3(request.form)
…验证()。。。
如果form.is_有效():
#做一些事情,保存到数据库
表格1.save()
表格2.save()
表格3.save()
返回HttpReturnRedirect(“/success_page/”)#在发布表单后始终重定向
#如果无效,请重新显示。
返回呈现模板('register.html',{'form':form,'hidden_forms':hidden_forms})
html(假设您对每个页面使用单个模板
{%csrf_令牌%}
{{form}}
{隐藏的\u表单%中的每个\u表单的百分比}
{{每种形式}
现在,当您的表单在步骤3中转到POST时,如果有效,则可以使用前面步骤中的每个表单数据


如果您想要一个鲁莽的解决方案(需要更多的工作),请仔细研究一下。

我个人建议使用session对象将数据从一个表单传递到另一个表单。如果您有少量数据,那么您可以不使用flask提供的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)

为什么不在每个步骤结束前将它们存储到数据库中?@m170897017这是可能的,但有点无聊。在这种情况下,我需要多次更新同一个注册表。在示例中,步骤2和步骤3只是sql更新,对吗?能否将表单的内容存储在一些类变量中,并在步骤3结束时将其保存到数据库中?能否解释一下在你的情况下,为什么你会认为使用
会话
是个坏主意?@Anzel会话的目的不是处理大块的表单数据。当然会有更聪明的方法。隐藏表单似乎比会话更糟糕。无论如何,我说的是flask和wtforms,而不是django。另外一种方法,可能我可以使用临时存储每个步骤的数据。Redis就是为此而设计的。我完全同意。我个人喜欢使用session对象,因为我的应用程序已经从session中检索到数据,这样看起来是一致的。但是使用flask Redis是一个完全有效的选择。我的表单“不可JSON序列化”的地方出现了错误你是如何克服的?这里也是@user805981@anvd表单对象本身是否可以JSON序列化?