When trying to upload a file and using an secure_filename function with Flask-WTF, I get the error TypeError: normalize() argument 2 must be str, not FileStorage. How do I fix this? Does this have something todo with my Posts table code? Also did I add to much code below?
I think the error is caused by this line.
filename_is_secure = secure_filename(picture_filename)
Here is the code
app.py
from flask import Flask, flash, render_template
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, TextAreaField, SubmitField
from wtforms.fields.html5 import EmailField
from wtforms import validators
from wtforms.fields.simple import FileField
from wtforms.validators import DataRequired, Length, ValidationError
from flask_wtf.file import FileField, FileRequired, FileAllowed
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy
import uuid
import os
app = Flask(__name__, template_folder='templates')
db = SQLAlchemy(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
app.config['SECRET_KEY'] = 'SomeKkey'
class FileForm(FlaskForm):
filename = FileField('image', validators=
[FileRequired() ,FileAllowed(['jpg', 'png'], 'Images only!') ])
submit = SubmitField('Submit')
app.config['UPLOAD_FOLDER'] = '\\path\\to\\the\\uploads'
class Posts(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
profile_pic_name = db.Column(db.String())
from werkzeug.utils import secure_filename
@app.route('/', methods=['GET', 'POST'])
def home():
form = FileForm()
if form.validate_on_submit():
picture_filename = form.filename.data
# This makes sure the filename is safe
filename_is_secure = secure_filename(picture_filename)
# make the file unique incase someone uploads the same name
# uuid is a random number generator
unique_filename = str(uuid.uuid1()) filename_is_secure
posts = Posts(profile_pic_name=unique_filename)
db.session.add(posts)
db.session.commit()
# save file to a secure location
picture_filename.save(os.path.join(app.config['UPLOAD_FOLDER'], unique_filename))
flash("You have succesfully uploaded your profile picture.")
return render_template('home.html', form=form, title='upload Profile Picture')
if __name__ == '__main__':
app.run(debug=True)
templates/home.py
<!DOCTYPE html>
<html>
<!--upload and update profile pics-->
<head>
<title> {{ title }} </title>
</head>
<body>
<form action="" method="POST" enctype="multipart/form-data">
{{ form.csrf_token }}
{{ form.filename }}
<input type="submit" value="Submit">
</form>
<!--make flash message work-->
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<p1> {{message}} </p1>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</body>
</html>
Here is the full error
Traceback (most recent call last):
File "C:\Users\nmyle\anaconda3\envs\py\Lib\site-packages\flask\app.py", line 2091, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\nmyle\anaconda3\envs\py\Lib\site-packages\flask\app.py", line 2076, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\nmyle\anaconda3\envs\py\Lib\site-packages\flask\app.py", line 2073, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\nmyle\anaconda3\envs\py\Lib\site-packages\flask\app.py", line 1518, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\nmyle\anaconda3\envs\py\Lib\site-packages\flask\app.py", line 1516, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\nmyle\anaconda3\envs\py\Lib\site-packages\flask\app.py", line 1502, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "C:\Users\nmyle\OneDrive\Desktop\testing code folder todo delete\code folder\app.py", line 62, in home
filename_is_secure = secure_filename(picture_filename)
File "C:\Users\nmyle\anaconda3\envs\py\Lib\site-packages\werkzeug\utils.py", line 456, in secure_filename
filename = unicodedata.normalize("NFKD", filename)
TypeError: normalize() argument 2 must be str, not FileStorage```
CodePudding user response:
Your picture_filename
variable is an instance of FileStorage, as this is what a WTForm FileField returns in its data attribute upon a successful upload.
Function secure_filename
takes a string type as its parameter, but you have passed a FileStorage
instance, hence the error.
Use the filename
attribute of the FileStorage
instance.
picture_file_storage = form.filename.data
filename_is_secure = secure_filename(picture_file_storage.filename)