I'm trying to make a page that will allow a user to download files that have been uploaded. Currently, I'm finding all of the files within a directory, passing them to the index page and printing them out. I then want each to have a download button, that when clicked will download the file relative to the file name. I cannot figure out how to pass the file name back through a URL so that I can use it on the download page.
import os
from flask import Flask, flash, render_template, url_for, request, redirect, send_from_directory, send_file, abort
from werkzeug.utils import secure_filename
import logging
UPLOAD_FOLDER = './uploads/'
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config["ALLOWED_EXTENSIONS"] = {'TXT', 'PDF', 'DOC', 'DOXC', 'BIBTEXT', 'DBLP'}
#app.route('/', methods=['POST', 'GET'])
def index():
if request.method == 'POST':
files = []
with os.scandir('uploads/') as entries:
for entry in entries:
files.append(entry)
return render_template('index.html', files=files)
else:
return render_template('index.html')
def allowed_ext(filename):
if not "." in filename:
return False
ext = filename.rsplit(".", 1)[1]
if ext.upper() in app.config["ALLOWED_EXTENSIONS"]:
return True
else:
return False
#app.route('/upload', methods=['POST','GET'])
def upload_file():
if request.method == "POST":
if request.files:
file = request.files['file']
if file.filename == "":
print("File name must not be blank")
return redirect(request.url)
if not allowed_ext(file.filename):
print("File extension not supported")
return redirect(request.url)
else:
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
print("File saved")
return render_template('index.html')
else:
return render_template('upload.html')
#app.route('/download/<file_name>', methods=['GET', 'POST'])
def download_file(file_name):
file_name = file_name
try:
return send_from_directory(app.config['UPLOAD_FOLDER'], filename=file_name, as_attachment=True)
except FileNotFoundError:
abort(404)
if __name__ == "__main__":
app.run(debug=True)
{% extends 'base.html' %}
{% block head%}<title>File thingy</title>{% endblock %}
{%block body%}
<h4 style='text-align: center;'> Directory Reader</h4>
{% if files is not defined %}
<h2 style='text-align: center;'>Click the button below to analyse the upload directory!</h4>
{% else %}
{% if files|length < 1 %}
<h2 style='text-align: center;'>No files found in this directory!</h4>
{% else %}
<table>
{% for file in files %}
<tr>
<td>{{file}}</td>
<td>
<a href='{{url_for(download_file, file_name=file)}}'>Download</a>
</tr>
{% endfor %}
</table>
{% endif %}
{% endif %}
<form action='/' method = 'POST'>
<input type='submit' name='submitbutton' value='See Files'>
</form>
<button type="button" ><a href='/upload'>Upload file!</a></button> {% endblock %}
Related
I am currently trying to upload a picture and later on process it. But I am getting an 405 error and I don't know how to fix it.
#app.route('/upload')
def upload():
return render_template('upload.html')
#app.route('/uploader', methods = ['GET', 'POST'])
def upload_f():
if request.method == 'POST':
f = request.files['file']
f.save(f.filename)
return 'file uploaded successfully'
The html form
<html>
<body>
<form action = "http://localhost:5000/uploader" method = "POST"
enctype = "multipart/form-data">
<input type = "file" name = "file" />
<input type = "submit"/>
</form>
</body>
</html>
From Miguel Grinberg's Handling File Uploads With Flask tutorial:
import imghdr
import os
from flask import Flask, render_template, request, redirect, url_for, abort, \
send_from_directory
from werkzeug.utils import secure_filename
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024
app.config['UPLOAD_EXTENSIONS'] = ['.jpg', '.png', '.gif']
app.config['UPLOAD_PATH'] = 'uploads'
def validate_image(stream):
header = stream.read(512) # 512 bytes should be enough for a header check
stream.seek(0) # reset stream pointer
format = imghdr.what(None, header)
if not format:
return None
return '.' + (format if format != 'jpeg' else 'jpg')
#app.route('/')
def index():
files = os.listdir(app.config['UPLOAD_PATH'])
return render_template('index.html', files=files)
#app.route('/', methods=['POST'])
def upload_files():
uploaded_file = request.files['file']
filename = secure_filename(uploaded_file.filename)
if filename != '':
file_ext = os.path.splitext(filename)[1]
if file_ext not in app.config['UPLOAD_EXTENSIONS'] or \
file_ext != validate_image(uploaded_file.stream):
abort(400)
uploaded_file.save(os.path.join(app.config['UPLOAD_PATH'], filename))
return redirect(url_for('index'))
#app.route('/uploads/<filename>')
def upload(filename):
return send_from_directory(app.config['UPLOAD_PATH'], filename)
<html>
<head>
<title>File Upload</title>
</head>
<body>
<h1>File Upload</h1>
<form method="POST" action="" enctype="multipart/form-data">
<p><input type="file" name="file"></p>
<p><input type="submit" value="Submit"></p>
</form>
<hr>
{% for file in files %}
<img src="{{ url_for('upload', filename=file) }}" style="width: 64px">
{% endfor %}
</body>
</html>
I have simple input field where user is adding note.. and what ever note user is adding it will be displayed above in the list.. and m trying to store in a session in flask
This is my flask code
from flask import Flask, render_template, request, session
from flask_session import Session
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
#app.route("/", methods=["GET", "POST"])
def index():
if session.get("notes") is None:
session["notes"]=[]
if request.method == "POST":
note = request.form.get("note")
session["notes"].append(note)
return render_template("session-index.html", notes=session["notes"])
if __name__ == "__main__":
app.run(debug=True)
And this is my html page
{% extends "inherit-layout.html" %}
{% block heading %}
Form Page
{% endblock %}
{% block body %}
<ul>
{% for note in notes %}
<li>{{ note }}</li>
{% endfor %}
</ul>
<form action="{{ url_for('index') }}" method="POST">
<input type="text" name="note" placeholder="Enter Note Here">
<button type="submit">Add Note</button>
</form>
{% endblock %}
What currently happening is when m adding note for second time it is replacing previous one in the list.
from flask import *
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
app.config['SECRET_KEY'] = "asddaffffa"
#app.route("/", methods=["GET", "POST"])
def index():
if session.get("notes") is None:
session["notes"]=[]
if request.method == "POST":
note = request.form.get("note")
list = session["notes"]
list.append(note)
session["notes"] = list
return render_template("session-index.html", notes=session["notes"])
if __name__ == "__main__":
app.run(debug=True)
This should work..
Error
while uploading files to my selected folder it raises the following error.
As I am new to flask I am unable to catch the error.
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
app.py
import os
#import magic
import urllib.request
#from app import app
from flask import Flask, flash, request, redirect, render_template
from werkzeug.utils import secure_filename
app = Flask(__name__)
#app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
UPLOAD_FOLDER = '/static'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/')
def upload_form():
return render_template('upload.html')
#app.route('/', methods=['POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the files part
if 'files[]' not in request.files:
flash('No file part')
return redirect(request.url)
files = request.files.getlist('files[]')
for file in files:
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
flash('File(s) successfully uploaded')
return redirect('/')
if __name__ == "__main__":
app.run(debug = True)
upload.html
<!doctype html>
<title>Python Flask Multiple Files Upload Example</title>
<h2>Select file(s) to upload</h2>
<p>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</p>
<form method="post" action="/" enctype="multipart/form-data">
<dl>
<p>
<input type="file" name="files[]" multiple="true" autocomplete="off" required>
</p>
</dl>
<p>
<input type="submit" value="Submit">
</p>
</form>
You should change your code
#app.route('/', methods=['POST', 'GET'])
def upload_file():
if request.method == 'POST':
# check if the post request has the files part
if 'files[]' not in request.files:
flash('No file part')
return redirect(request.url)
files = request.files.getlist('files[]')
for file in files:
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
flash('File(s) successfully uploaded')
return redirect('/')
elif request.method == 'GET':
return render_template('upload.html')
I am trying to upload a csv file into Mysql with choosing the correspanding columns but the problem is that once I change the route, the file is closed.
So I tried to render 2 templates in the same route: the first to load the file and the second to choose the columns. I can access only the first template.
I am testing the second form with env.is_submitted() but even when I am not submitting it prints "submitted"
#app.route('/upload', methods=['GET', 'POST'])
def upload():
form = UploadForm()
global columnscsv, salessource
if form.validate_on_submit():
try:
filename = secure_filename(form.csv.data.filename)
file = form.csv.data
if file and allowed_file(filename):
print 'file_path'
salessource = CSVSource(file, delimiter=',')
columnscsv = salessource.fieldnames
print columnscsv
finally:
return render(salessource)
return render_template('upload.html', form=form)
def render(salessource):
env = envForm()
if env.is_submitted():
print "submitted"
return render_template('form.html',columnscsv = columnscsv ,env =env)
upload.html
<html>
<head>
<title>Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" >
{{ form.hidden_tag() }}
{{ form.csv }}
<input type="submit">
</form></body>
</html>
form.html
{% block body %}
<form name = "mapping" method="POST" enctype="multipart/form-data" >
{{ env.hidden_tag() }}
<table>
{% for csv in columnscsv %}
<tr> <td> {{ csv }}</td>
<td><select name = "{{ csv }}" >
<option >year </option>
<option >month</option>
<option >day</option>
<option>reference</option>
<option>designation</option>
</select></td>
</tr>
{% endfor %}
</table>
<input type="submit" value="Submit" name = "submit" >
</form>
{% endblock %}
Your form.html can only be rendered when you submit a form (your render(salessource) was inside the check of submit form), so I cant find anyway it does not print "Submitted" in this way.
If you want to render 2 templates, I find a work arround like this:
Add session['fileName'] = filename as a temp to know if a file was submitted
Redirect back to itself after submit
Check if session['fileName'] exist to choose what template to render
#app.route('/upload', methods=['GET', 'POST'])
def upload():
form = UploadForm()
global columnscsv, salessource
if form.validate_on_submit():
try:
filename = secure_filename(form.csv.data.filename)
file = form.csv.data
session['fileName'] = filename
if file and allowed_file(filename):
print 'file_path'
salessource = CSVSource(file, delimiter=',')
columnscsv = salessource.fieldnames
print columnscsv
redirect(url_for('upload'))
except:
raise
if session.get('fileName') != None:
render_template('form.html',columnscsv = columnscsv ,env=env)
else:
return render_template('upload.html', form=form)
I am new to Flask and web applications in general. I have images that could be located in different locations:
-directory1
-image1
-directory2
-subdirectory
-image2
-directory3
-flask_app
-app.py
-static
The purpose of the app is to dynamically provide access to the content in other directories which is not static and subject to change for each user. The content cannot be moved or modified.
How do I display images from other directories within the app without moving or modifying them based on input values from the user?
I have the following so far but the image link is broken:
from flask import Flask, render_template, request, send_from_directory
current_filepath = /directory2/image{}.png
app = Flask(__name__, static_url_path='')
#app.route('/js/<path:filename>')
def download_file(filename):
return send_from_directory('js', filename)
#app.route('/', methods=['GET','POST'])
def print_form():
if request.method == 'POST':
test = current_filepath.format(request.form['image_num'])
return render_template('form.html', result=test)
if request.method == 'GET':
return render_template('form.html')
if __name__ == '__main__':
app.run(debug=True)
With the following form.html file:
<!DOCTYPE html>
<html lang="en">
<body>
<form method="POST" action=".">
<input id="post_form_id" name="image_num" value="" />
<input type="submit">
</form>
{% if result %}
{{ url_for('download_file', filename= result) }}
<img src={{ url_for('download_file', filename= result) }}>
{% endif %}
</body>
</html>
app/
app.py
...
uploads/
dir1/
img1.png
...
...
app.config['UPLOAD_FOLDER'] = 'path/to/uploads/dir1'
#app.route('/file/<path:filename>')
def img_file(filename):
filename = filename + '.png'
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
#app.route('/', methods=['GET', 'POST'])
def index():
filename = None
if request.method == 'POST':
filename = request.form['img_num']
return render_template('form.html', filename=filename)
<form method="post" action="" >
<input type="text" id="form_id" name="img_num">
<input type="submit" value="submit">
</form>
{% if filename %}
<img src=" {{ url_for('img_file', filename=filename) }}">
{% endif %}