目前,使用 Flask,我有一个主页,其中包含一个(长)表单供用户填写。但是,我想将此表单分成多个块,并使用“下一步”按钮迭代它们(有点像当您在线购买商品时必须浏览不同的页面来填写您的信息)。到目前为止,我已经尝试过以下方法:
在主页html中实现多个“提交”按钮:
{% extends 'layout.html' %}
{% block body %}
<div class="content-section">
<form method="POST" action="">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Pipeline Input</legend>
<div class="form-group required">
{{ form.stack_name.label(class="form-control-label") }}
{{ form.deploy_bucket(class="form-control form-control-lg") }}
</div>
<div class="form-group required">
{{ form.key_pair.label(class="form-control-label") }}
{{ form.key_pair(class="form-control form-control-lg") }}
</div>
<div class="form-group required">
{{ form.start_point.label(class="form-control-label") }}
{{ form.start_point(class="form-control form-control-lg") }}
</div>
<div class="form-group">
{{ form.qc.label(class="form-control-label") }}
{{ form.qc(class="form-control form-control-lg") }}
</div>
{{ form.submit_1(class="btn btn-outline-info") }}
<div class="form-group required">
{{ form.input_uri.label(class="form-control-label") }}
{{ form.input_uri(class="form-control form-control-lg") }}
</div>
<div class="form-group required">
{{ form.output_uri.label(class="form-control-label") }}
{{ form.output_uri(class="form-control form-control-lg") }}
</div>
<div class="form-group required">
{{ form.ref_uri.label(class="form-control-label") }}
{{ form.ref_uri(class="form-control form-control-lg") }}
</div>
<div class="form-group required">
{{ form.user_assets_uri.label(class="form-control-label") }}
{{ form.user_assets_uri(class="form-control form-control-lg") }}
</div>
{{ form.submit_2(class="btn btn-outline-info") }}
<div class="form-group">
{{ form.target.label(class="form-control-label") }}
{{ form.target(class="form-control form-control-lg") }}
</div>
<div class="form-group required">
{{ form.package_name.label(class="form-control-label") }}
{{ form.package_name(class="form-control form-control-lg") }}
</div>
<div class="form-group required">
{{ form.license_name.label(class="form-control-label") }}
{{ form.license_name(class="form-control form-control-lg") }}
</div>
{{ form.submit_final(class="btn btn-outline-info") }}
</div>
</fieldset>
</div class="form-group">
</div>
</form>
<p>{{ error }}</p>
</div>
{% endblock %}
这里是定义表单输入的地方:
from flask_wtf import FlaskForm
from wtforms import StringField, TextField, SubmitField, IntegerField, SelectField, validators
class InputForm(FlaskForm):
stack_name = StringField('STACK NAME', validators=[validators.required()])
deploy_bucket = SelectField('DEPLOYMENT BUCKET', validators=[validators.required()])
key_pair = SelectField('KEY PAIR', validators=[validators.required()])
start_point = SelectField('START POINT', validators=[validators.required()], choices=[("", "---"), ("", "fastq"), ("", "bam"), ("", "hdof"), ("", "gvcf"), ("", "vcf")])
qc = SelectField('QC', choices=[("", "---"), ("","BAM"), ("","VCF")])
submit_1 = SubmitField('Next')
input_uri = StringField('INPUT BUCKET', validators=[validators.required()])
output_uri = StringField('OUTPUT BUCKET', validators=[validators.required()])
ref_uri = SelectField('REFERENCE BUCKET', validators=[validators.required()])
user_assets_uri = StringField('USER ASSETS BUCKET', validators=[validators.required()])
submit_2 = SubmitField('Next')
target = StringField('TARGET')
package_name = StringField('PACKAGE NAME', validators=[validators.required()])
license_name = StringField('LICENSE NAME', validators=[validators.required()])
submit_final = SubmitField('Execute Pipeline')
这是我的app.py,其中处理表单数据。目前它仍然设置为只有一个提交按钮,所以我不确定如何处理这里的“下一个”按钮/分页:
@app.route('/', methods=['GET', 'POST'])
def pipeline():
form = InputForm(request.form)
form.deploy_bucket.choices = [("", "---")] + [("", bucket["Name"]) for bucket in app.config['S3_CLIENT'].list_buckets()["Buckets"]]
form.ref_uri.choices = [("", "---")] + [("", bucket["Name"]) for bucket in app.config['S3_CLIENT'].list_buckets()["Buckets"]]
form.key_pair.choices = [("", "---")] + [("", pair["KeyName"]) for pair in app.config['EC2_CLIENT'].describe_key_pairs()["KeyPairs"]]
if request.method == 'POST':
STACK_NAME = form.stack_name.data
DEPLOY_BUCKET = form.deploy_bucket.data
KEY_PAIR = form.key_pair.data
START_POINT = form.start_point.data
QC = form.qc.data
INPUT_URI = form.input_uri.data
OUTPUT_URI = form.output_uri.data
REF_URI = form.ref_uri.data
USER_ASSETS_URI = form.user_assets_uri.data
TARGET = form.target.data
PACKAGE_NAME = form.package_name.data
LICENSE_NAME = form.license_name.data
flash('The pipeline has been executed!', 'success')
dic = {
"STACK_NAME": STACK_NAME,
"DEPLOY_BUCKET": DEPLOY_BUCKET,
"KEY_PAIR": KEY_PAIR,
"START_POINT": START_POINT,
"QC": QC,
"INPUT_URI": INPUT_URI,
"OUTPUT_URI": OUTPUT_URI,
"REF_URI": REF_URI,
"USER_ASSETS_URI": USER_ASSETS_URI,
"LOCAL_ASSETS_DIR": LOCAL_ASSETS_DIR,
"SAMPLE_FILE": SAMPLE_FILE,
"TARGET": TARGET,
"PACKAGE_NAME": PACKAGE_NAME,
"LICENSE_NAME": LICENSE_NAME,
}
proc = subprocess.Popen('pwd', shell=True, stdout=subprocess.PIPE)
with open("input.json", 'w') as f:
json.dump(dic, f)
proc = subprocess.Popen('python pipeline.py -p', shell=True, stdout=subprocess.PIPE)
return redirect(url_for('dashboard'))
return render_template('pipeline.html', title='Pipeline Input', form=form)
@app.route('/dashboard')
def dashboard():
return render_template('dashboard.html')
如果您坚持使用 Flask 来完成此任务,最简单的方法是将您的表单分成多个表单,也许按类别。处理完一个表单后,您的 Flask 代码将重定向到下一个表单。
但是,特别是在 2018 年,这可能应该在客户端而不是服务器端完成。原因是你这里的问题实际上与负责处理表单的Flask无关,而是与负责显示表单的前端有关。
优点很多。其一,您可以一次加载整个表单,但每次显示的内容都分块。这将允许您通过仅提交一个表单来保持 Flask 代码简单,但可以让您精确控制向用户显示的内容。此外,您还减少了从客户端到服务器的往返次数,这将为您的用户提供更好的性能。
如果您希望避免编写字体端分页代码,可以将一些解决方案集成到您的表单中。我个人使用了Bootstrap的分页功能并取得了巨大成功。
我遇到了类似的问题,最终使用 JavaScript 在客户端解决了这个问题:https://uublog.de/simple-pagination-in-wtforms/