我在两个表单上有一个隐藏字段,它们在同一页面上呈现。此隐藏字段的default
设置为true
。我使用这个隐藏字段来测试已提交的表单;已提交的表单会将该字段的值设置为true
,而另一个表单不会设置该字段。
但是,在提交一个表单(每个表单的操作是同一页面)后,另一个字段的隐藏字段的value
将设置为空白。例如:
首先,渲染的字段是这样的(当然,每个字段都以它们自己的形式):
<input id="upload-submitted" name="upload-submitted" type="hidden" value="true">
...other stuff...
<input id="process-submitted" name="process-submitted" type="hidden" value="true">
如果我提交第一个表单,它会将我带到同一页面,并且字段呈现如下:
<input id="upload-submitted" name="upload-submitted" type="hidden" value="true">
...other stuff...
<input id="process-submitted" name="process-submitted" type="hidden" value="">
如果我提交第二个表单,那么除了第一个input
没有value
且第二个表单具有正确的值之外,一切都是相同的。
问题,具体而言,似乎是在提交后,data
字段的submitted
字段为空,如果该表单未提交 - 这是有道理的,&#39;什么让我确定哪个表格真的提交了。但是,字段不会重置以在HTML中呈现 - 这意味着我无法在提交另一个表单后提交其他表单。
如何防止这种情况发生?有没有更好的方法来确定在页面上提交了哪两种表单?
这是我的forms.py:
class HiddenSubmitted(object):
"""A mixin to provide a hidden field called "submitted" which has a default
value of "true".
"""
submitted = HiddenField(default="true")
class ButtonWidget(object):
"""A widget to conveniently display buttons.
"""
def __call__(self, field, **kwargs):
if field.name is not None:
kwargs.setdefault('name', field.name)
if field.value is not None:
kwargs.setdefault('value', field.value)
kwargs.setdefault('type', "submit")
return HTMLString('<button %s>%s</button>' % (
html_params(**kwargs),
escape(field._value())
))
class ButtonField(Field):
"""A field to conveniently use buttons in flask forms.
"""
widget = ButtonWidget()
def __init__(self, text=None, name=None, value=None, **kwargs):
super(ButtonField, self).__init__(**kwargs)
self.text = text
self.value = value
if name is not None:
self.name = name
def _value(self):
return str(self.text)
class MultiCheckboxField(SelectMultipleField):
"""
A multiple-select, except displays a list of checkboxes.
Iterating the field will produce subfields, allowing custom rendering of
the enclosed checkbox fields.
"""
widget = ListWidget(prefix_label=False)
option_widget = CheckboxInput()
class DocumentUploadForm(Form, HiddenSubmitted):
"""This is a form to upload files to the server. It handles both XML
and JSON files, and is used by the document_upload view.
"""
upload_button = ButtonField(text="Upload", name="action")
uploaded_file = FileField("File", validators=[
FileRequired("You must select a file"),
FileAllowed(app.config["ALLOWED_EXTENSIONS"])
])
class ProcessForm(Form, HiddenSubmitted):
"""
Allows the user to select which objects should be
processed/deleted/whatever.
"""
PROCESS = "0"
DELETE = "-1"
files = MultiCheckboxField("Select", coerce=int, validators=[
Required("You must select at least one item from the table.")
])
process_button = ButtonField("Process", name="action", value=PROCESS)
delete_button = ButtonField("Delete", name="action", value=DELETE)
def validate_files(form, field):
if form.process_button.data == form.PROCESS:
# There must be a JSON file selected
struc_count = 0
doc_count = 0
for selected_file in form.files.data:
unit = session.query(Unit).\
filter(Unit.id == selected_file).one()
ext = os.path.splitext(unit.path)[1][1:]
if ext in app.config["STRUCTURE_EXTENSION"]:
struc_count += 1
else:
doc_count += 1
if struc_count is not 1:
raise ValidationError("Must be exactly one structure file")
if doc_count < 1:
raise ValidationError("At least one document must be selected")
和我的views.py:
def really_submitted(form):
""" WTForms can be really finnicky when it comes to checking if a form
has actually been submitted, so this method runs validate_on_submit()
on the given form and checks if its "submitted" field has any data. Useful
for pages that have two forms on them.
:arg Form form: A form to check for submission.
:returns boolean: True if submitted, false otherwise.
"""
if form.submitted.data == "true":
return form.validate_on_submit()
return False
@app.route(app.config["PROJECT_ROUTE"] + "<project_id>",
methods=["GET", "POST"])
def project_show(project_id):
"""
Show the files contained in a specific project. It also allows the user
to upload a new document, much like projects().
:param int project_id: The ID of the desired project.
"""
upload_form = forms.DocumentUploadForm(prefix="upload")
process_form = forms.ProcessForm(prefix="process")
# If I put a print statement here, I find that by now one field has no data for the hidden field, which makes sense
# The template needs access to the ID of each file and its filename.
process_form.files.choices = []
file_objects = #blah blah database stuff
# First handle the actions of the upload form
if shortcuts.really_submitted(upload_form):
uploaded_files = request.files.getlist("upload-uploaded_file")
for uploaded_file in uploaded_files:
filename = secure_filename(uploaded_file.filename)
dest_path = os.path.join(app.config["UPLOAD_DIR"],
str(project_id), filename)
uploaded_file.save(dest_path)
unit = Unit(path=dest_path, project=project_id)
unit.save()
process_form.files.choices.append((unit.id,
os.path.split(dest_path)[1]))
# Or what happened with the document selection
elif shortcuts.really_submitted(process_form):
files = request.form.getlist("process-files")
if request.form["action"] == process_form.DELETE:
# Delete every selected file, its database record, and item in
# the listing
for file_id in files:
file_model = session.query(Unit).\
filter(Unit.id == file_id).one()
file_name = os.path.split(file_model.path)[1]
os.remove(file_model.path)
session.delete(file_model)
session.commit()
process_form.files.choices.remove((int(file_id), file_name))
elif request.form["action"] == process_form.PROCESS:
#TODO: process these files.
pass
return render_template("document_list.html",
upload_form=upload_form,
process_form=process_form)
答案 0 :(得分:0)
在呈现模板之前,至少有一个解决方案:
process_button.submitted.data = "true"
delete_button.submitted.data = "true"