Flask WTF在失败时通过验证
我有一个Flask应用程序,在失败时通过用户输入验证。我在应用程序的另一部分中也有类似的代码,可以正常工作。似乎没有调用FileAllowed()方法。如果是的话,那就是真的 这段代码将用户文件上传到s3 MultipleFileField()方法仅对图像文件扩展名进行验证检查。但是,任何文件都通过此检查。InputRequired()方法工作得很好 我尝试了多种不同的方法,但都没有效果。这不是一个CRSF问题,因为其他具有类似代码的路由在没有它的情况下工作 烧瓶/水处理设施表格:Flask WTF在失败时通过验证,flask,flask-wtforms,wtforms,Flask,Flask Wtforms,Wtforms,我有一个Flask应用程序,在失败时通过用户输入验证。我在应用程序的另一部分中也有类似的代码,可以正常工作。似乎没有调用FileAllowed()方法。如果是的话,那就是真的 这段代码将用户文件上传到s3 MultipleFileField()方法仅对图像文件扩展名进行验证检查。但是,任何文件都通过此检查。InputRequired()方法工作得很好 我尝试了多种不同的方法,但都没有效果。这不是一个CRSF问题,因为其他具有类似代码的路由在没有它的情况下工作 烧瓶/水处理设施表格: cl
class AddImgForm(FlaskForm): # should use InputRequired() not DataRequired()
images= MultipleFileField('Upload Images', validators=[InputRequired(),FileAllowed(['jpg', 'png', 'jpeg', 'tif'])])
submitBTN2 = SubmitField('Upload')
路线:
@users.route("/account", methods=['GET', 'POST'])
@login_required
def account():
form = UpdateAccountForm()
if form.validate_on_submit():
if form.picture.data: # if a picture is provided save picture
picture_file= save_picture(form.picture.data, 'p') # saves picture and returns dict with ['filepath'] and ['filename']
BUCKET= os.environ['BUCKET'] # should send to 'bucket-publicaccess/uploads' bucket in production
s3= boto3.resource("s3",
region_name = "us-east-2", # had to add "us-east-2" as incorrect region was generated
config= boto3.session.Config(signature_version='s3v4'), # must add this to address newer security
aws_access_key_id = os.environ["AWS_ACCESS_KEY_ID"],
aws_secret_access_key = os.environ["AWS_SECRET_ACCESS_KEY"]) # AWS Generated key pairs
s3.Bucket(BUCKET).upload_file(picture_file['filepath'], 'uploads/'+ picture_file['filename']) #upload to s3
current_user.image_file= 'uploads/'+picture_file['filename']
print(current_user.image_file)
os.remove(picture_file['filepath']) # remove file from tmp directory
current_user.username = form.username.data
current_user.email = form.email.data
db.session.commit() # commit changes
flash('Your account has been updated!', 'success')
return redirect(url_for('users.account'))
elif request.method == 'GET':
form.username.data = current_user.username
form.email.data = current_user.email
image_file = current_user.image_file
return render_template('account.html', title='Account',
image_file=image_file, form=form)
HTML:
<form method="POST" action="" enctype="multipart/form-data" id="addImgForm">
{{ addImgForm.hidden_tag() }}
<fieldset class="form-group">
<div class="form-group">
{{ addImgForm.images.label() }}
{{ addImgForm.images(class="form-control-file") }}
{% if addImgForm.images.errors %}
{% for error in addImgForm.images.errors %}
<span class="text-danger">{{ error }}</span></br>
{% endfor %}
{% endif %}
</div>
<div class="form-group">
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
{{ addImgForm.submitBTN2(class="btn btn-outline-info") }}
</div>
</fieldset>
</form>
{{addImgForm.hidden_tag()}}
{{addImgForm.images.label()}}
{{addImgForm.images(class=“form control file”)}
{%if addImgForm.images.errors%}
{addImgForm.images.errors%中的错误为%0}
{{error}}
{%endfor%}
{%endif%}
接近
{{addImgForm.submitbttn2(class=“btn btn outline info”)}
如果您有任何帮助,我们将不胜感激,因为大多数问题都与此失败有关,而此代码总是通过 问题在于
FileAllowed
验证器,它在验证时需要一个FileStorage
实例,而MultipleFileField
将FileStorage
实例列表传递给验证器。您可以通过编写自己的验证器来克服这一问题,例如:
class MultiFileAllowed(object):
def __init__(self, upload_set, message=None):
self.upload_set = upload_set
self.message = message
def __call__(self, form, field):
# FileAllowed only expects a single instance of FileStorage
# if not (isinstance(field.data, FileStorage) and field.data):
# return
# Check that all the items in field.data are FileStorage items
if not (all(isinstance(item, FileStorage) for item in field.data) and field.data):
return
for data in field.data:
filename = data.filename.lower()
if isinstance(self.upload_set, Iterable):
if any(filename.endswith('.' + x) for x in self.upload_set):
return
raise StopValidation(self.message or field.gettext(
'File does not have an approved extension: {extensions}'
).format(extensions=', '.join(self.upload_set)))
if not self.upload_set.file_allowed(field.data, filename):
raise StopValidation(self.message or field.gettext(
'File does not have an approved extension.'
))
使用Flask、Flask WTF和Flask Boostrap的简单单文件示例:
from collections import Iterable
from flask_bootstrap import Bootstrap
from flask import Flask, redirect, url_for, render_template_string
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed
from markupsafe import Markup
from werkzeug.datastructures import FileStorage
from wtforms.fields import MultipleFileField, SubmitField
from wtforms.validators import InputRequired, StopValidation
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
Bootstrap(app)
class MultiFileAllowed(object):
def __init__(self, upload_set, message=None):
self.upload_set = upload_set
self.message = message
def __call__(self, form, field):
if not (all(isinstance(item, FileStorage) for item in field.data) and field.data):
return
for data in field.data:
filename = data.filename.lower()
if isinstance(self.upload_set, Iterable):
if any(filename.endswith('.' + x) for x in self.upload_set):
return
raise StopValidation(self.message or field.gettext(
'File does not have an approved extension: {extensions}'
).format(extensions=', '.join(self.upload_set)))
if not self.upload_set.file_allowed(field.data, filename):
raise StopValidation(self.message or field.gettext(
'File does not have an approved extension.'
))
class ImagesForm(FlaskForm):
images = MultipleFileField(
'Upload Images',
validators=[
InputRequired(),
MultiFileAllowed(['jpg', 'png', 'jpeg', 'tif'])
]
)
submit = SubmitField('Upload')
upload_template = '''
{% import "bootstrap/wtf.html" as wtf %}
<form method="POST" enctype="multipart/form-data">
{{ wtf.quick_form(form) }}
</form>
'''
@app.route('/')
def index():
return Markup("<a href='uploads'>Go to the uploads<a>")
@app.route('/uploads', methods=['GET', 'POST'])
def upload():
form = ImagesForm()
if form.validate_on_submit():
if form.images:
for image in form.images.data:
print 'Uploaded File: {}'.format(image.filename)
return redirect(url_for('index'))
else:
print form.errors
return render_template_string(upload_template, form=form)
if __name__ == '__main__':
app.run()
从集合导入Iterable
从flask_引导导入引导
从烧瓶导入烧瓶,重定向,url,呈现模板字符串
来自flask_wtf进口FlaskForm
允许从flask_wtf.file导入文件
从markupsafe导入标记
从werkzeug.datastructures导入文件存储
从wtforms.fields导入MultipleFileField、SubmitField
从wtforms.validators导入需要的输入,停止验证
app=烧瓶(名称)
app.config['SECRET_KEY']='123456790'
引导(应用程序)
允许类多文件(对象):
def uuu init uuuu(自我,上传集,消息=无):
self.upload\u set=上传\u set
self.message=消息
定义调用(自身、表单、字段):
如果不是(field.data和field.data中的项的全部(isinstance(项,文件存储)):
返回
对于field.data中的数据:
filename=data.filename.lower()
如果isinstance(self.upload\u set,Iterable):
如果有(self.upload\u集合中x的filename.endswith('.'+x)):
返回
提升停止验证(self.message或field.gettext)(
'文件没有批准的扩展名:{extensions}'
).format(扩展名=','.join(self.upload_set)))
如果不是self.upload\u set.file\u允许(field.data,filename):
提升停止验证(self.message或field.gettext)(
“文件没有批准的扩展名。”
))
类别图像窗体(烧瓶窗体):
图像=多字段(
“上传图像”,
验证器=[
InputRequired(),
允许多文件(['jpg','png','jpeg','tif'])
]
)
submit=SubmitField(‘上传’)
上传模板=“”
{%import“bootstrap/wtf.html”作为wtf%}
{{wtf.quick_form(form)}
'''
@应用程序路径(“/”)
def index():
返回标记(“转到上载”)
@app.route('/uploads',methods=['GET','POST'])
def upload():
form=ImagesForm()
if form.validate_on_submit():
如果是form.images:
对于form.images.data中的图像:
打印“上载的文件:{}”。格式(image.filename)
返回重定向(url_for('index'))
其他:
打印表单错误
返回渲染模板字符串(上传模板,表单=表单)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
app.run()
问题在于FileAllowed
验证器,它在验证时需要一个FileStorage
实例,而multiplefield
将FileStorage
实例列表传递给验证器。您可以通过编写自己的验证器来克服这一问题,例如:
class MultiFileAllowed(object):
def __init__(self, upload_set, message=None):
self.upload_set = upload_set
self.message = message
def __call__(self, form, field):
# FileAllowed only expects a single instance of FileStorage
# if not (isinstance(field.data, FileStorage) and field.data):
# return
# Check that all the items in field.data are FileStorage items
if not (all(isinstance(item, FileStorage) for item in field.data) and field.data):
return
for data in field.data:
filename = data.filename.lower()
if isinstance(self.upload_set, Iterable):
if any(filename.endswith('.' + x) for x in self.upload_set):
return
raise StopValidation(self.message or field.gettext(
'File does not have an approved extension: {extensions}'
).format(extensions=', '.join(self.upload_set)))
if not self.upload_set.file_allowed(field.data, filename):
raise StopValidation(self.message or field.gettext(
'File does not have an approved extension.'
))
使用Flask、Flask WTF和Flask Boostrap的简单单文件示例:
from collections import Iterable
from flask_bootstrap import Bootstrap
from flask import Flask, redirect, url_for, render_template_string
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed
from markupsafe import Markup
from werkzeug.datastructures import FileStorage
from wtforms.fields import MultipleFileField, SubmitField
from wtforms.validators import InputRequired, StopValidation
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
Bootstrap(app)
class MultiFileAllowed(object):
def __init__(self, upload_set, message=None):
self.upload_set = upload_set
self.message = message
def __call__(self, form, field):
if not (all(isinstance(item, FileStorage) for item in field.data) and field.data):
return
for data in field.data:
filename = data.filename.lower()
if isinstance(self.upload_set, Iterable):
if any(filename.endswith('.' + x) for x in self.upload_set):
return
raise StopValidation(self.message or field.gettext(
'File does not have an approved extension: {extensions}'
).format(extensions=', '.join(self.upload_set)))
if not self.upload_set.file_allowed(field.data, filename):
raise StopValidation(self.message or field.gettext(
'File does not have an approved extension.'
))
class ImagesForm(FlaskForm):
images = MultipleFileField(
'Upload Images',
validators=[
InputRequired(),
MultiFileAllowed(['jpg', 'png', 'jpeg', 'tif'])
]
)
submit = SubmitField('Upload')
upload_template = '''
{% import "bootstrap/wtf.html" as wtf %}
<form method="POST" enctype="multipart/form-data">
{{ wtf.quick_form(form) }}
</form>
'''
@app.route('/')
def index():
return Markup("<a href='uploads'>Go to the uploads<a>")
@app.route('/uploads', methods=['GET', 'POST'])
def upload():
form = ImagesForm()
if form.validate_on_submit():
if form.images:
for image in form.images.data:
print 'Uploaded File: {}'.format(image.filename)
return redirect(url_for('index'))
else:
print form.errors
return render_template_string(upload_template, form=form)
if __name__ == '__main__':
app.run()
从集合导入Iterable
从flask_引导导入引导
从烧瓶导入烧瓶,重定向,url,呈现模板字符串
来自flask_wtf进口FlaskForm
允许从flask_wtf.file导入文件
从markupsafe导入标记
从werkzeug.datastructures导入文件存储
从wtforms.fields导入MultipleFileField、SubmitField
从wtforms.validators导入需要的输入,停止验证
app=烧瓶(名称)
app.config['SECRET_KEY']='123456790'
引导(应用程序)
允许类多文件(对象):
def uuu init uuuu(自我,上传集,消息=无):
self.upload\u set=上传\u set
self.message=消息
定义调用(自身、表单、字段):
如果不是(field.data和field.data中的项的全部(isinstance(项,文件存储)):
返回
对于field.data中的数据:
filename=data.filename.lower()
如果isinstance(self.upload\u set,Iterable):
如果有(self.upload\u集合中x的filename.endswith('.'+x)):
返回
提升停止验证(self.message或field.gettext)(
'文件没有批准的扩展名:{extensions}'
).format(扩展名=','.join(self.upload_set)))
如果不是self.upload\u set.file\u允许(field.data,filename):
提升停止验证(self.message或field.gettext)(
“文件没有批准的扩展名。”
))
类别图像窗体(烧瓶窗体):
图像=多字段(
“上传图像”,