Reading input file and processing it in flask - python

I'm trying to write a simple flask program that will create a web page in which it receives a file (by uploading it), and then using that file's data and displaying a filtered part of it in my web page, I just cant seem to understand how to do that.
This is the code I used to upload the file, which worked fine.
import os
from flask import Flask, request, redirect, url_for
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = 'C:/Users/ohadt/PycharmProjects/logFiles'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'log'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# if user does not select file, browser also
# submit a empty part without filename
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('read_uploaded_file',
filename=filename))
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
'''
Then I tried writing the method for opening the file and reading the data from it, but I couldn't figure how to do that, could you please help me understand how to read the file content and presenting a filtered version of it on my site?
Thanks!

You already saved it here
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
just open it up and read as you work with any other files, example:
#app.route('/read_file', methods=['GET'])
def read_uploaded_file():
filename = secure_filename(request.args.get('filename'))
try:
if filename and allowed_filename(filename):
with open(os.path.join(app.config['UPLOAD_FOLDER'], filename)) as f:
return f.read()
except IOError:
pass
return "Unable to read file"
You need to carefully sanitize user input here, otherwise method could be used to read something unintended (like app source code for example). Best is just not grant user ability to read arbitrary files - for example when you save a file, store it's path in database with some token and give user just this token:
filename = secure_filename(file.filename)
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
token = store_in_db(filepath)
return redirect(url_for('read_uploaded_file',
token=token))
Then accept a token, not a filename when you read a file:
#app.route('/read_file', methods=['GET'])
def read_uploaded_file():
filepath = get_filepath(request.args.get('token'))
try:
if filepath and allowed_filepath(filepath):
with open(filepath) as f:
return f.read()
except IOError:
pass
return "Unable to read file"
Tokens need to be random, long, not guessable (uuid4 for example) - otherwise there will be a possibility to easily read other users files. Or you need to store relation between file and user in database and check it too. Finally, you need to control size of file uploads to prevent user from uploading huge files (app.config['MAX_CONTENT_LENGTH']) and control amount of info you read in memory when you display "filtered" file content (f.read(max_allowed_size)).

Related

flask check if user selected a file to upload

I've checked on stackoverflow and other places and everywhere they use files.filename to check if a file is available or not. If I do this I get the message
AttributeError: 'list' object has no attribute 'filename'
Do I miss something? Or is there another way to check if the user has selected a file to upload?
my HTML:
<form method="POST" enctype="multipart/form-data" action="/upload">
<label>Choose a problem report file (*.zip).
<input type="file" name="file[]" multiple="" accept=".zip">
<input type="submit" value="Upload problem report(s)">
</label>
</form>
my python
import flask
from werkzeug.wrappers import request
import os
app = flask.Flask("upload")
UPLOAD_FOLDER = './upload'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def get_html(page_name):
html_file = open(page_name + ".html")
content = html_file.read()
html_file.close()
return content
#app.route("/upload", methods=["POST"])
def upload():
files = flask.request.files.getlist("file[]")
if files.filename !='':
for file in files:
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
return get_html("index")
It's not the best code I know, but if I leave out the check for the filename the upload works.
It should be something like this:
files = flask.request.files.getlist("file[]")
for file in files:
if file.filename !='':
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
As the error message suggested, your get a list, and a list has not filename attribute, so you need to check the items in the list.

Uploading xml file and processing using flask

I am developing a Python backend to which I send an xml file from the front end. This is so that I can generate python code based on it and show the contents in the front end. How can I do this using flask?
I have attached the code I tried below. It does not work for me. I was not able to save the xml file into a directory.
from flask import Flask, request, render_template
app = Flask(__name__, template_folder='templates')
from main import run
import os
#app.route('/')
def home():
return render_template('home.html')
#app.route('/submit/', methods=['POST'])
def upload():
if request.method == 'POST':
uploaded_file = xmltodict.parse(request.get_data())
file = os.path.join(app.config['upload'].uploaded_file.filename)
uploaded_file.save(file)
return "Successfully uploaded"
#app.route('/submit/')
def convert():
path='upload'
os.chdir(path)
for file in os.listdir():
if file.endswith(".py"):
file_path = f"{path}\{file}"
run(file_path,'tmp','python')
return "Code generated"
#app.route('/view/')
def view_python_script():
# Folder path
path='tmp'
os.chdir(path)
content=""
for file in os.listdir():
if file.endswith(".py"):
file_path = f"{path}\{file}"
with open(file_path, "r") as f:
content = content + f.read().replace('\n','<br>')
return render_template('upload.html', details=content)
if __name__ == "__main__":
app.run(port=3000, debug=True)
I occupy this: uploaded_file = request.files ['file_upload'].
file_upload I pass it from the html with the parameter name = "file_upload" of input contained within the form.
The problem I have is that when I want to share it in another html page it closes and throws me a ValueError: I / O operation on closed file.
But well, I hope it helps you !!!

How do I save a image using a flask API then return it to my React App can use it

I am trying to use my Flask API to save an image to the database OR just a file system but this is something I have never done and am getting nowhere with it.
I would like to be able to return the image back when the route is called and be able to use it in my ReactJS Application using just a img tag.
All I have been able to find is how to save the image to the Database and then download it using a route. I need to be able to return it. (It works just not what I need.)
Here is what that was:
#app.route('/img-upload', methods=['POST'])
def img_upload():
file = request.files['image']
newFile = Mealplan(name=file.filename, data=file.read())
db.session.add(newFile)
db.session.commit()
return jsonify({"Done!" : "The file has been uploaded."})
#app.route('/get-mealplan-image/<given_mealplan_id>')
def download_img(given_mealplan_id):
file_data = MealPlan.query.filter_by(id=given_mealplan_id).first()
return send_file(BytesIO(file_data.data), attachment_filename=file_data.name, as_attachment=True)
Save the files on the file system will be a more proper method. Here is a minimal example:
from flask import send_from_directory
basedir = os.path.abspath(os.path.dirname(__file__))
uploads_path = os.path.join(basedir, 'uploads') # assume you have created a uploads folder
#app.route('/img-upload', methods=['POST'])
def upload_image():
f = request.files['image']
f.save(os.path.join(uploads_path , f.filename)) # save the file into the uploads folder
newFile = Mealplan(name=f.filename) # only save the filename to database
db.session.add(newFile)
db.session.commit()
return jsonify({"Done!" : "The file has been uploaded."})
#app.route('/images/<path:filename>')
def serve_image(filename):
return send_from_directory(uploads_path, filename) # return the image
In your React app, you can use the filename to build to the image URL: /images/hello.jpg
Update:
If you can only get the id, the view function will be similar:
#app.route('/get-mealplan-image/<given_mealplan_id>')
def download_img(given_mealplan_id):
file_data = MealPlan.query.filter_by(id=given_mealplan_id).first()
return send_from_directory(uploads_path, file_data.name)

cv2.imread is blocking flow

am trying to read an image using cv2.imread() but the flow just block there and never returns, tried to read already-existing files but got same issue, am not sure what is the reason is
#app.route('/api/upload', methods=['GET', 'POST'])
def upload_file():
print('request method is {}'.format(request.method))
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
print('file not in request.files')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
print('filename is {}'.format(file.filename))
return redirect(request.url)
print(file and allowed_file(file.filename))
if file and allowed_file(file.filename):
print('receiving ... ', file.filename)
filename = secure_filename(file.filename)
ts = int(time.time())
file_name = file_name_template.format(ts, filename)
print(file_name)
filePath = os.path.join(app.root_path, app.config['UPLOAD_FOLDER'], file_name)
file.save(filePath)
print('reading image')
cv2.imread(filePath)
return 'done' #never executed
note : this is a flask application running on WAMP server + WSGI
I believe this has been answered already in another posting. Also see http://blog.rtwilson.com/how-to-fix-flask-wsgi-webapp-hanging-when-importing-a-module-such-as-numpy-or-matplotlib/.
Basically, it's not using the main interpreter to run the cv2.imread, which isn't running properly in a sub-interpreter.

How to rename upload image while uploading - Flask / Python

I´m building a website where people should be able to add small adds with pictures. All pictures go to the same directory. So I need to rename the pictures so there wont be any overrides or conflicts.
When I´m adding an add to the website its auto increment the add_id. I want to use this add_id for the picture name.
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/aufgeben', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
titel = request.form['titel']
beschreibung = request.form['beschreibung']
kategorie = request.form['kategorie']
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# if user does not select file, browser also
# submit a empty part without filename
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
# Anzeigeninhalt in DB eintragen
cursor = g.con.cursor()
cursor.execute('insert into anzeigen (titel, beschreibung, kategorie) values (%s, %s, %s)',
(titel, beschreibung, kategorie))
g.con.commit()
cursor.close()
flash("Anzeige aufgegeben.")
return render_template('aufgeben.html',)
Thanks for all help. Maybe someone have a better idea how to solve this?
I know it might be too late for a response but maybe someone else will look for an answer. As Nishant Nawarkhede replied, you can use timestamp to rename the files uploaded. Since I came accross the same need I used the following piece of code to rename the files while uploading:
NOW = datetime.datetime.now()
new_filename = os.path.join(UPLOAD_FOLDER, file.filename.rsplit('.',1)[0] + '_' + NOW.strftime("%d_%m_%Y_%H_%M_%S") + '.' + file.filename.rsplit('.',1)[1])
After this, your files should look like the following format:
'path_to_file/filename_datetime.jpg'

Categories