Why is if request.method == 'POST' and 'photo' in request.files - python

I have this little example script. It gets a file from a HTML an uploads it to the server. That part works just fine. Please see the script below.
I would like to take some action if no file is selected in the form. I thought the following would evaluate to false if no file was selected in the HTML form, but it seams to be always true.
if request.method == 'POST' and 'photo' in request.files:
Either a file is selected or not 'Text to print' is returned.
What am I missing here?
Any hint is appreciated.
Best regards
Kresten
from flask import Flask, render_template, request
from flask_uploads import UploadSet, configure_uploads, IMAGES
app = Flask(__name__)
photos = UploadSet('photos', IMAGES)
app.config['UPLOADED_PHOTOS_DEST'] = 'static'
configure_uploads(app, photos)
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST' and 'photo' in request.files:
filename = photos.url(request.files['photo'])
fil = request.files['photo']
return 'Text to print'
return render_template('upload.html')
if __name__ == '__main__':
app.run(debug=True)
app.run(host='0.0.0.0')
The HTML template:
<html>
<head>
<title>Upload</title>
</head>
<body>
<form method=POST enctype=multipart/form-data action="{{ url_for('upload') }}">
<input type=file name=photo>
<input type="submit">
</form>
</body>
</html>
(Thanks to Danila for saving my day)

In your case photo always will be in request.files, but filename not(can be empty string). Just change condition to:
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST' and request.files['photo'].filename:
filename = photos.url(request.files['photo'])
fil = request.files['photo']
return 'Text to print'
return render_template('upload.html')

Related

Flask returns 'Method not allowed' when submitting form

I am closely following the very brief tutorial from Flask-wtf here. I have an issue where after I submit my name in my submit page form, it gives a "405 Method Not Allowed" message instead of directing me to the success page.
from flask import Flask, render_template, redirect
from forms import MyForm
app = Flask(__name__)
app.secret_key = 'mysecretKey'
#app.route('/submit', methods=('GET', 'POST'))
def submit():
form = MyForm()
if form.validate_on_submit():
return redirect('/success')
return render_template('submit.html', form=form)
#app.route('/success')
def success():
return "Well done for entering your name!"
if __name__ == '__main__':
app.run(debug=True)
My form is here:
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired
class MyForm(FlaskForm):
name = StringField('name', validators=[DataRequired()])
My submit.html code is shown below (just like in the tutorial):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Password page</title>
</head>
<body>
<form method="POST" action="/">
{{ form.hidden_tag() }}
{{ form.name.label }} {{ form.name(size=20) }}
<input type="submit" value="Go">
</form>
</body>
</html>
EDIT: The if form.validate_on_submit() condition does not return True so the contents of the loop do not execute. I added a simple print statement in it which didn't execute.
I'd be lying if I pretended to know exactly how all relative paths are resolved. However, you can fix this by changing:
<form method="POST" action="/">
to:
<form method="POST" action="{{ url_for('submit') }}">
It's one of those things that it really does make sense to pass the issue off to the library to figure out. Use url_for which also works in Jinja2 when rendering the template.
The problem is you are not mentioning that the method success should handle POST requests.
from flask import Flask, render_template, redirect
from forms import MyForm
app = Flask(__name__)
app.secret_key = 'mysecretKey'
#app.route('/submit', methods=('GET', 'POST'))
def submit():
form = MyForm()
if form.validate_on_submit():
return redirect('/success')
return render_template('submit.html', form=form)
#app.route('/success')
def success():
return "Well done for entering your name!"
if __name__ == '__main__':
app.run(debug=True)
with
from flask import Flask, render_template, redirect
from forms import MyForm
app = Flask(__name__)
app.secret_key = 'mysecretKey'
#app.route('/submit', methods=['GET', 'POST'])
def submit():
form = MyForm()
if form.validate_on_submit():
return redirect('/success')
return render_template('submit.html', form=form)
# This is the change I made.
#app.route('/success', methods=['POST'])
def success():
return "Well done for entering your name!"
if __name__ == '__main__':
app.run(debug=True)

How to upload excel or csv file to flask as a Pandas data frame?

I have been trying to upload a csv/excel file as pandas data frame on a flask application. I am not able to find any method which could help upload the file as a data frame. Below is the code used.
from flask import Flask, request, render_template
from werkzeug import secure_filename
import pandas as pd
app = Flask(__name__)
#app.route('/upload')
def upload():
return render_template('upload.html')
#app.route('/uploader',methods = ['GET','POST'])
def uploader():
if request.method == 'POST':
#f = request.files['file']
df = pd.read_csv(request.files.get('file'))
#f.save(secure_filename(f.filename))
#df = pd.DataFrame(eval(f))
return print(df.shape)
if __name__ == '__main__':
app.run(debug = True)
You didn't provide a template you're using in your code (upload.html).
Also return print(...) returns None and None is not a valid response from a Flask view.
Here's a working example:
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
Shape is: {{ shape }}
</body>
</html>
app.py
from flask import Flask, request, render_template
import pandas as pd
app = Flask(__name__)
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
df = pd.read_csv(request.files.get('file'))
return render_template('upload.html', shape=df.shape)
return render_template('upload.html')
if __name__ == '__main__':
app.run(debug=True)
dummy.csv
id,name,surname
1,John,Doe
2,Jane,Doe
Result after uploading dummy.csv:

Flask, How can I response the picture on the page

I am new to Flask and web development, I want to upload a picture and process it by my deep learning application and then response the processed picture on the page, here is my frame work code
# coding: utf-8
import os
import uuid
import PIL.Image as Image
from werkzeug import secure_filename
from flask import Flask, url_for, render_template, request, url_for, redirect, send_from_directory
ALLOWED_EXTENSIONS = set(list(['png', 'jpg', 'jpeg']))
UPLOAD_FOLDER = '/tmp'
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def process_image(file_path):
"""
resize image to 32x32
:param file_path: file path
:return:
"""
img = Image.open(file_path, mode='r')
return img.resize([32,32], Image.ANTIALIAS)
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET', 'POST'])
def upload_file():
_path = None
if request.method == 'POST':
_file = request.files['file']
print(_file)
if _file and allowed_file(_file.filename):
filename = secure_filename(_file.filename)
_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
_file.save(_path)
return show_pic(deep_learning(_path))
return '''
<!DOCTYPE html>
<title>Web App/title>
<h1>Deep Learning Web App</h1>
<form action="/" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
'''
#app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
if __name__ == '__main__':
app.run()
As you can see it, I have implemented upload picture function and the function deep_learning(path), and it return the path of processed picture, I need to implement function show_pic(), how can I do that?
Create a template with your html skeleton and pass the image path to the render_template() function.
result.html
<html>
<img src="{{ image_path }}">
</html>
Add this to your view function:
return render_template('result.html', image_path=deep_learning(_path))
For this to work your files need to be located in the staticdirectory or a subdirectory.
Or you can define _file(processed file) with None value below form tag check if file not none then show it:
#app.route('/', methods=['GET', 'POST'])
def upload_file():
_path = None
_file = None
if request.method == 'POST':
_file = request.files['file']
print(_file)
if _file and allowed_file(_file.filename):
filename = secure_filename(_file.filename)
_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
_file.save(_path)
return '''
<!DOCTYPE html>
<title>Web App/title>
<h1>Deep Learning Web App</h1>
<form ...>
...
</form>
{% if _file%}
<img src="{{url_for('uploaded_file', filename=_file) }}" >
{% endif %}
'''

how to upload multiple files using flask in python

Here is my code for multiple files upload:
HTML CODE:
Browse <input type="file" name="pro_attachment1" id="pro_attachment1" multiple>
PYTHON CODE:
pro_attachment = request.files.getlist('pro_attachment1')
for upload in pro_attachment:
filename = upload.filename.rsplit("/")[0]
destination = os.path.join(application.config['UPLOAD_FOLDER'], filename)
print "Accept incoming file:", filename
print "Save it to:", destination
upload.save(destination)
But it uploads a single file instead of multiple files.
How to
In the template, you need to add mulitple attribute in upload input:
<form method="POST" enctype="multipart/form-data">
<input type="file" name="photos" multiple>
<input type="submit" value="Submit">
</form>
Then in view function, the uploaded files can get as a list through request.files.getlist('photos'). Loop this list and call save() method on each item (werkzeug.datastructures.FileStorage) will save them at given path:
import os
from flask import Flask, request, render_template, redirect
app = Flask(__name__)
app.config['UPLOAD_PATH'] = '/the/path/to/save'
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST' and 'photo' in request.files:
for f in request.files.getlist('photo'):
f.save(os.path.join(app.config['UPLOAD_PATH'], f.filename))
return 'Upload completed.'
return render_template('upload.html')
Furthermore, you may need to use secure_filename() to clean filename:
# ...
from werkzeug.utils import secure_filename
# ...
for f in request.files.getlist('photo'):
filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_PATH'], filename))
# ...
You can also generate a random filename with this method.
Full demo
View:
import os
from flask import Flask, request, render_template
from werkzeug.utils import secure_filename
app = Flask(__name__)
app.config['UPLOAD_PATH'] = '/the/path/to/save'
#main.route('/upload', methods=['GET', 'POST'])
def upload():
form = UploadForm()
if form.validate_on_submit() and 'photo' in request.files:
for f in request.files.getlist('photo'):
filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_PATH'], filename))
return 'Upload completed.'
return render_template('upload.html', form=form)
Form:
from flask_wtf import FlaskForm
from wtforms import SubmitField
from flask_wtf.file import FileField, FileAllowed, FileRequired
class UploadForm(FlaskForm):
photo = FileField('Image', validators=[
FileRequired(),
FileAllowed(photos, 'Image only!')
])
submit = SubmitField('Submit')
Template:
<form method="POST" enctype="multipart/form-data">
{{ form.hidden_tag() }}
{{ form.photo(multiple="multiple") }}
{{ form.submit }}
</form>
More
For better upload experience, you can try Flask-Dropzone.
Your code looks perfect.
I think the only mistake your making is splitting and taking the first value.
And also i dont know about the rsplit(), but the split() works perfect for me.
HTML CODE
<input id="upload_img" name="zip_folder" type="file" multiple webkitdirectory >
PYTHON CODE
#app.route('/zipped',methods = ['GET', 'POST'])
def zipped():
if request.method == 'POST':
f = request.files.getlist("zip_folder")
print f
for zipfile in f:
filename = zipfile.filename.split('/')[1]
print zipfile.filename.split('/')[1]
zipfile.save(os.path.join(app.config['ZIPPED_FILE'], filename))
return render_template('final.html')

flask wtforms, what input is pressed

Flask beginner here, bear with me please !
In this little piece of code I simplified for the question, I have for a defined route / with 2 forms : I'd like the add form to add things to the db and the delete form to delete things, simple.
However my issue is that in this code I can't differentiate which input button from the form is pressed as formadd.validate() and formdel.validate() both always return true.
How can I differentiate which submit button is pressed in order to manipulate the database accordingly ?
At first I wrote what is currently commented below, but obviously it doesn't work since the validate method returns true....
from flask import Flask, render_template, request
from flask.ext.sqlalchemy import SQLAlchemy
from wtforms import Form, StringField
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///botdb.db'
db = SQLAlchemy(app)
class BotFormAdd(Form):
botname = StringField('bot name')
botdescription = StringField('bot description')
class BotFormDelete(Form):
botid = StringField('bot id')
#app.route('/', methods=['GET', 'POST'])
def index():
formadd = BotFormAdd(request.form)
formdel = BotFormDelete(request.form)
if request.method == 'POST':
print(formadd.validate(), formdel.validate())
# if request.method == 'POST' and formadd.validate():
# print('in formadd')
# bot = Bot(name=formadd.botname.data, description=formadd.botdescription.data)
# db.session.add(bot)
# db.session.commit()
# return redirect(url_for('index'))
# if request.method == 'POST' and formdel.validate():
# print('in formdel')
# db.session.delete(formdel.botid.data)
# db.session.commit()
# return redirect(url_for('index'))
return render_template('index.html', title='Home', formadd=formadd, formdel=formdel)
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>this is a test</title>
</head>
<body>
<form method=post action="/">
<dl>
{{ formadd.botname }}
{{ formadd.botdescription }}
</dl>
<p><input type=submit name='add' value='add this'>
</form>
<form method=post action="/">
<dl>
{{ formdel.botid }}
</dl>
<p><input type=submit name='delete' value='delete this'>
</form>
</body>
</html>
There's lots of ways of doing this, but it breaks down into two categories-- either you indicate it via the route, or via an element on a form.
Most people would just add separate routes:
#app.route('/delete-bot/', methods=['post'])
def delete_bot():
form = BotFormDelete()
if form.validate():
delete_bot(id=form.botid.data)
flash('Bot is GONE')
return redirect(url_for('index'))
So your delete form would submit to that route, get processed and sent back to index.
<form method='post' action='url_for('delete_bot')>
And you'd have a different route for adding a bot.
Alternatively you could check what type of form it was from it's contents. E.g.
if request.form.get('botid'):
# it has a botid field, it must be a deletion request
form = BotFormDelete()
form.validate()
delete_bot(form.botid.data)
else:
form = BotFormAdd()
....
But that way seems like it would get messy quickly.

Categories

Resources