I am trying to upload an image from a form to a database in Flask in a practice e-commerce website I am working on. I am using flask-uploads to handle the file uploads since it seems easier than other ways of uploading files. I am getting the following error "NameError: name 'images' is not defined". This error seems to be occurring within the routes.py file which handles the functions and routing of the website. I will list the main parts of the code below. The add_item function within the routes.py file takes what has been submitted by the form and sends that data to the database. As I said, this is where the error is occurring since images cannot be recognized but I can't figure out how to solve the issue. Init.py is a package that holds where the flask-uploads connection is made. Config.py is used to define the configurations for the application. The addItem function within the forms.py file is used to layout the structure of the form. An HTML file which is not included in this document because I don't think it is linked to the issue uses the form structure in forms.py to display the form to the screen.
I have tried looking up the solution online but there aren't very detailed solutions to this issue and the documentation of Python Flask is already limited enough but Flask-Upload does not have very good documentation especially not in regards to being used with databases. I am new to Python Flask so if anyone could help me with this issue that would be greatly appreciated.
routes.py:
#addItem page
@app.route('/add_Item',methods=["GET","POST"])
add_Item():
form = addItem()
if form.validate_on_submit():
filename = images.save(request.files['image'])
url = images.url(filename)
item = Item(title=form.name.data,price=form.price.data,description=form.description.data,stock=form.stock.data,vendorid=current_user.id,image=url)
db.session.add(item)
db.session.commit()
flash("Congratulations, your item has been added")
return redirect(url_for('vendor',username=current_user.username))
else:
return render_template('addItem.html', title="Add Item", form=form)
init.py:
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_uploads import UploadSet, IMAGES, configure_uploads
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
login = LoginManager(app)
# Configure the image uploading via Flask-Uploads
images = UploadSet('images', IMAGES)
configure_uploads(app, images)
from app import routes, models, errors
config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
TOP_LEVEL_DIR = os.path.abspath(os.curdir)
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'abcdef'
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
UPLOADS_DEFAULT_DEST = TOP_LEVEL_DIR + '/app/static/img/'
UPLOADS_DEFAULT_URL = 'http://localhost:5000/static/img/'
UPLOADED_IMAGES_DEST = TOP_LEVEL_DIR + '/app/static/img/'
UPLOADED_IMAGES_URL = 'http://localhost:5000/static/img/'
forms.py
class addItem(FlaskForm):
name = StringField('Name',validators=[DataRequired()])
price = IntegerField('Price',validators=[DataRequired()])
description = StringField('Description',validators=[DataRequired()])
stock = IntegerField('Stock',validators=[DataRequired()])
image = FileField('Image', validators=[FileRequired(), FileAllowed(images, 'Images only!')])
submit = SubmitField('Submit',validators=[DataRequired()])
Try this
f = request.files['image']
f.save(secure_filename(f.filename))
url = f.filename
Here you can see the i used secured_filename() against your file name. this is to prevent directory tranversal attack.
url is the filename and image will be saved on the same directory as your application code.
Finally your code will look like below
#addItem page
@app.route('/add_Item',methods=["GET","POST"])
add_Item():
form = addItem()
if form.validate_on_submit():
f = request.files['image']
f.save(secure_filename(f.filename))
url = f.filename
item = Item(title=form.name.data,price=form.price.data,description=form.description.data,stock=form.stock.data,vendorid=current_user.id,image=url)
db.session.add(item)
db.session.commit()
flash("Congratulations, your item has been added")
return redirect(url_for('vendor',username=current_user.username))
else:
return render_template('addItem.html', title="Add Item", form=form)
For more advance security on files upload. then read up link