Flask - wtforms:使用' filerrequied() '验证器验证失败,即使没有表单错误



我是Flask的新手。我读了很多书,但还是找不到解决办法。

当我注释掉FileField (pic)的验证器时,代码工作得很好。使用验证器-没有form.errors,但仍然form.validate_on_submit()为假。

编辑:

  • 如果我只使用FileAllowed验证器,那么form.validate_on_submit()是True,即使文件类型不是'png'…
  • 如果我只使用FileRequired()验证器,form.validate_on_submit()为False。

这是main.py的相关部分:

import os
from flask import Flask, render_template, request, redirect, url_for
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_wtf.file import FileField, FileRequired, FileAllowed
from flask_wtf.csrf import CSRFProtect,CSRFError
#from werkzeug.utils import secure_filename
app = Flask(__name__)
# Flask-WTF requires an encryption key - the string can be anything
app.config['SECRET_KEY'] = 'nydtnvbkadjshnvcksdnvcld'
app._static_folder = 'D:/a/b/c/static'
#app.config['UPLOAD_FOLDER'] = 'D:/a/b/c/uploads/'
app.debug = True
# Flask-Bootstrap requires this line
Bootstrap(app)
ANALYSIS_FOLDER = 'D:/a/b/c/analysis/'
##########################  test  ###########################################
class NameForm(FlaskForm):
name = StringField('Which actor is your favorite?', validators=[DataRequired()])
pic = FileField('Picture of actor:',
validators=[FileRequired(), FileAllowed(['png'], 'png files only!')]
)
submit = SubmitField('Submit')
@app.route('/test', methods=['GET', 'POST'])
def test():
form = NameForm(request.form)
print(form.errors)
print(form.validate_on_submit())
if form.validate_on_submit():
print('Hello')
# create a folder for the new dataset
new_n = dataset_number(ANALYSIS_FOLDER)
data_path = os.path.join(ANALYSIS_FOLDER, 'data' + str(new_n))
print(data_path)
os.mkdir(data_path)
# save name
with open(os.path.join(data_path, 'name_of_actor.txt'), 'w') as text_file:
text_file.write(form.name.data)
uploaded_file = request.files['pic']
print(uploaded_file)
if uploaded_file:
print(uploaded_file.filename)
uploaded_file.save(os.path.join(data_path, 'file.png'),)
return redirect(url_for('home'))
#return f'''<h1> {form.name.data} is a great actor! </h1>'''
return render_template('test.html', form=form)

这是base.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<style>
.formdesign {
background-color: #BFC9CA;
color: black;
margin: 10px;
padding: 5px;
}
</style>
{% block head %} {% endblock %}
</head>
<body style="background-color:#BFC9CA">
{% block body %} {% endblock %}
</body>
</html>

这是test.html:

{% extends 'base.html' %}
{% block head %}
<title>Test</title>
{% endblock %}
{% block body %}
<h1>Test!</h1>
<form method="POST" action="" enctype="multipart/form-data">
{{ form.csrf_token() }}
<div class="form-row">
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.name.label }}</label>
{{ form.name }}
<p> Names are super important. </p>
</div>
<hr>
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.pic.label }}</label>
{{ form.pic }}
<p> Pictures are also super important. </p>
</div>
<div class="form-group">
{{ form.csrf_token() }}
{{ form.submit(class="btn btn-primary")}}
</div>
</div>
</form>
{% endblock %}

WTForms错误在字段上。如果你想访问它,你需要使用form.pic.errors

查看文档,例如:https://flask-wtf.readthedocs.io/en/0.15.x/quickstart/#validating-forms

我使用flask-Uploads解决了这个问题。

我的main.py现在看起来像这样:

import os
from flask import Flask, render_template, request, redirect, url_for
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_wtf.file import FileField, FileRequired, FileAllowed
from flask_uploads import UploadSet, configure_uploads, patch_request_class, IMAGES
ANALYSIS_FOLDER = 'D:/a/b/c/analysis/'
app = Flask(__name__)
# Flask-WTF requires an encryption key - the string can be anything
app.config['SECRET_KEY'] = 'nydtnvbkadjshnvcksdnvcld'
app.config['UPLOADED_PHOTOS_DEST'] = ANALYSIS_FOLDER
app._static_folder = 'D:/a/b/c/static'
app.debug = True
# Flask-Bootstrap requires this line
Bootstrap(app)
photos = UploadSet('photos', IMAGES)
configure_uploads(app, (photos))
##########################  test   ###########################################
class NameForm(FlaskForm):
name = StringField('Which actor is your favorite?', validators=[DataRequired()])
pic = FileField('Picture of actor:',
validators=[FileRequired(), FileAllowed(photos, 'images only!')]
)
submit = SubmitField('Submit')
@app.route('/test', methods=['GET', 'POST'])
def test():
form = NameForm(request.form)
#if form.validate_on_submit():
if request.method == 'POST' and 'pic' in request.files:
print('Hello')
new_n = dataset_number(ANALYSIS_FOLDER)
data_path = os.path.join(ANALYSIS_FOLDER, 'data' + str(new_n))
print(data_path)
os.mkdir(data_path)
# save e-mail
with open(os.path.join(data_path, 'name_of_actor.txt'), 'w') as text_file:
text_file.write(form.name.data)
filename = photos.save(storage=request.files['pic'], folder='data' + str(new_n), name='pic.')
print(filename)
return redirect(url_for('home'))
return render_template('test.html', form=form)

Andtest.html:

{% extends 'base.html' %}
{% block head %}
<title>Test</title>
{% endblock %}
{% block body %}
<h1>Test!</h1>
<form method="POST" action="{{ url_for('test') }}" enctype="multipart/form-data">
{{ form.csrf_token() }}
<div class="form-row">
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.name.label }}</label>
{{ form.name }}
<p> Names are super important. </p>
</div>
<hr>
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.pic.label }}</label>
{{ form.pic }}
<p> Pictures are also super important. </p>
</div>
<hr>
<div class="form-group">
{{ form.csrf_token() }}
{{ form.submit(class="btn btn-primary")}}
</div>
</div>
</form>
{% endblock %}

我也遇到过同样的问题。原来Flask-WTF上的文档说:

记住将HTML表单的enctype设置为multipart/form-data,否则,请求。文件将为空。

最新更新