How to upload a file without changing the page - python

I want to upload a file in server and perform operation on that file. I am using Flask to render a template which shows a form to select a file and upload using post operation. I am also using websockets to communicate between server and client. What i want to do is:
Show index.html
User selects a file
Click on submit button
File is uploaded but url doesn't change i.e. it still shows index.html
(it redirects to /uploads)
Status is changed using websockets
Currently, what's happening is the python upload_file function requires me to return something like "File uploaded successfully" which is changing view. If i redirect to the index.html from there, a new session is created.(I may be wrong here)
Contents of index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask SocketIO Test</title>
</head>
<body>
<p>Anacall</p>
<form action="/upload" method="POST"
enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit"/>
</form>
<br>
<p id="status">Status</p>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on('connect', function() {
socket.emit('get_status')
console.log('Websocket connected!');
});
socket.on('response_status',function(){
document.getElementById("status").innerHTML = "Status : File Status";
console.log("response received");
});
</script>
</body>
</html>
Contents of python file:
from flask import Flask, render_template, request, redirect, url_for
from flask_socketio import SocketIO, emit
from werkzeug import secure_filename
app = Flask(__name__)
socketio = SocketIO(app)
UPLOAD_FOLDER = '/static'
ALLOWED_EXTENSIONS = set(['xlsx', 'txt'])
status = None
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
return 'No file selected'
file = request.files['file']
if file.filename == '':
return "No file selected"
if file and allowed_file(file.filename):
file.save(secure_filename("file.xlsx")) # saves in current directory
status = "File uploaded"
return redirect(url_for('index'))
#socketio.on('get_status')
def send_status():
print("Send status now")
if (status != None):
emit("response_status")
if __name__ == '__main__':
socketio.run(app, host='10.131.65.115', port=12000)

You are right. Every time when you are reloading a page, the WebSocket-connection is closed and reopened again. To get rid of this you have to authenticate the session with session-cookies etc.
But you could just write return ('', 204) in the upload_file-Method of your python-file. This tells the client (Browser) that there is no content. The "upload"-Operation could than be realized within an iFrame.
But I would recommend you the use of DropzoneJS.
Examples with Flask:
https://github.com/greyli/flask-dropzone
https://github.com/helloflask/flask-upload-dropzone

Related

How to display and edit text files on the web page using python and Flask?

I want to build a simple web application based on Flask and Python for displaying and editing a text file in my directory path that I have created before on the web page. I have written the codes and can be run, but the results are not as expected. Everyone who can give me solutions is really appreciated.
from flask import Flask, request, render_template, redirect, url_for
from pathlib import Path
from os import listdir
app = Flask(__name__)
#app.route('/')
def my_form():
return render_template('index.html')
#app.route('/', methods=['GET,POST'])
def my_form_post():
path=Path('/users/Devie Andriyani/EditFlask/days.txt') # set the path to your file here
if not path.exists():path.touch()
input_days = request.form['text_box']
if request.method == 'POST':
with open('/users/Devie Andriyani/EditFlask/days.txt', 'w') as f:
f.write(request.form.get('text_box',None))
return redirect(url_for('my_form_post'))
if __name__ == '__main__':
app.debug = True
app.run()
<!DOCTYPE html>
<head>
<title>Hello</title>
</head>
<body>
<form action="" method="POST">
<input name="text_box" value={{days}}>
<input type="submit">
</form>
</body>
</html>
And here's the result. I don't get the result as I expected. It should edit a text file
from flask import Flask, request, render_template
from os import listdir
app = Flask(__name__)
#app.route('/')
def my_form():
return render_template('index.html')
#app.route('/', methods=['GET,POST'])
def my_form_post():
input_days = ''
if request.method == 'POST':
input_days = request.form['text_box']
with open('/users/Devie Andriyani/EditFlask/days.txt', 'w') as f:
f.write(str(input_days))
return render_template('index.html', days=input_days)
if __name__ == '__main__':
app.debug = True
app.run()
<!DOCTYPE html>
<head>
<title>Hello</title>
</head>
<body>
<form action="" method="POST">
<input name="text_box" value="{{ days }}">
<input type="submit">
</form>
</body>
</html>
I don't understand clearly what is your question but I have found some Erorrs in your code:
This is wrong
#app.route('/', methods=['GET,POST'])
you should write like this #app.route('/', methods=['GET','POST'])
also you didn't specify any element to display the days so then why you didn't see the output .
you should give some element like <p>{{days}}</p>

How can I use requests library to upload files to flask web page with a python script?

I made a simple Flask app where I can upload a file on a web page and it gets saved on my PC. I am able to upload files using browser.
This is the Web page Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
{{ form.csrf_token }}
{{ form.images }}
<button type="submit">Upload</button>
</form>
</body>
</html>
And This is the Flask App Code
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import FileField
from flask_uploads import configure_uploads, IMAGES, UploadSet
app = Flask(__name__, template_folder="templates")
app.config["SECRET_KEY"] = "secret"
app.config["UPLOADED_IMAGES_DEST"] = "img"
images = UploadSet("images", IMAGES)
configure_uploads(app, images)
class MyForm(FlaskForm):
images = FileField("images")
#app.route("/", methods = ["GET", "POST"])
def index():
if form.validate_on_submit():
print(form.images.data)
filename = images.save(form.images.data)
return f"Fileame: { filename }"
return render_template("template.html", form = MyForm())
You can use something like this. It will forward to another server. warning there is poor error checking here. This will upload from flask to flask server.
#route('/', methods=['GET', 'POST'])
def index(self):
if request.method == 'GET':
return render_template('index.html')
if request.method == 'POST':
uploaded_file = request.files['file']
task_id = random.getrandbits(16)
if not uploaded_file:
logging.info("[+] No tweet data supplied.")
return render_template('index.html')
try:
response = requests.post("{}/".format("www.someotherhost.com"), files={'file': (uploaded_file.filename, uploaded_file.stream, uploaded_file.content_type, uploaded_file.headers)})
if response != "Success":
print("do something here.")
except Exception as error:
logging.info("[-]", str(error))
return render_template('index.html')
return redirect(url_for('view:get_task_status', task_id=task_id))
Pass a files argument to the requests.post method which should be a dictionary where the key is 'images' as defined in your server app, and the value is the file pointer:
import requests
def upload(filename):
headers={'ContentType': 'multipart/form-data'}
with open(filename,'rb') as f:
files = {'images': f}
url='http://localhost:5000/'
r = requests.post(url, files=files)
print (r.content, r.status_code)
upload('some_file.jpg')

After flask redirect i have invalid data

I want to use Dropzone.js with Flask. After uploading file i want save file and show uploaded file name in another page (after redirect). But in browser i receive file name equals "sample_value". How to fix this?
Python
import os
from flask import Flask, render_template, request,redirect, url_for
app = Flask(__name__)
app.config['UPLOADED_PATH'] = os.getcwd() + '/upload'
#app.route('/')
def index():
# render upload page
return render_template('index.html')
#app.route('/upload', methods=['GET', 'POST'])
def upload():
n='sample_value'
if request.method == 'POST':
for f in request.files.getlist('file'):
n=f.filename
f.save(os.path.join(app.config['UPLOADED_PATH'], f.filename))
print(f.filename)
# There i get real file name
n=f.filename
return redirect(url_for('found', file_name=n), code=307)
#app.route('/found',methods=['GET', 'POST'])
def found():
#There my file name is "sample_value"
print('File name after redirect ', request.args.get('file_name'))
return request.args.get('file_name')
if __name__ == '__main__':
app.run(host='0.0.0.0', port =5000, debug=True, threaded=True)
Template
<html>
<body>
<script src="{{ url_for('static', filename='js/dropzone.js') }}"></script>
<script src="{{ url_for('static', filename='js/jquery.js') }}"></script>
<form action="{{ url_for('upload') }}" class="dropzone" id="my-dropzone" method="POST" enctype="multipart/form-data">
</form>
<script>
Dropzone.autoDiscover = false;
$(function() {
var myDropzone = new Dropzone("#my-dropzone");
myDropzone.on("queuecomplete", function(file) {
// Called when all files in the queue finish uploading.
window.location = "{{ url_for('upload') }}";
});
})
</script>
</body>
</html>
How i understand redirection executes before processing request?
I assume that you do not specify the method in your Dropzone, then it uses GET method by default. Check the Dropzone documentation and specify the method as POST.
n="sample_value"
if request.method == 'POST': # This is always false.
...
>>> print(n) # n has never been replaced
sample_value

How to run a python script in the background on click of html button using flask framework

''' upload.html'''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2 style="color:DodgerBlue;">File Uploader</h2>
<form id = "upload-form" action = "{{ url_for('upload') }}" method="POST"
enctype="multipart/form-data">
<input type = "file" name = "file" accept = "files/*" multiple>
<input type = "submit" value = "submit">
</form>
</body>
</html>
''' app.py'''
import os
from flask import Flask, request, render_template, send_from_directory
app = Flask(__name__)
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
#app.route("/")
def index():
return render_template("upload.html")
#app.route("/upload", methods=["POST"])
def upload():
target = os.path.join(APP_ROOT, 'Athena_XML_files/')
print(target)
if not os.path.isdir(target):
os.mkdir(target)
for file in request.files.getlist("file"):
print(file)
filename = file.filename
destination = "/".join([target, filename])
print(destination)
file.save(destination)
return render_template("complete.html")
#app.route('/run_script')
def run_script():
app.config.from_pyfile("main.py")
return render_template('result.html')
if __name__ == "__main__":
app.run(port=4555, debug=True)
'''complete.html'''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>XML files Uploaded</h1>
<ul><br><br>
<h2><strong>Please click to obtain the result</strong></h2><br><br>
<ul class="nav nav-stacked">
<li role="presentation"><a href="{{ url_for('run_script') }}">CLICK
HERE</a></li>
</ul>
</ul>
</body>
</html>
As the XML files are uploaded and the CLICK HERE button is clicked, main.py file should run in the background for which i have made a function in app.py file to run the main.py file.
Uploading works well, but on click of button the main.py file is not running in the background.
I'm not sure if your idea is a good one. I posted some small solutions, but you should read this article for a better practice.
1) If you want to run an external script from inside flask, you could use subprocess to run a script from the command line.
#app.route('/run-script')
def run_script():
result = subprocess.check_output("python main.py", shell=True)
return render_template('results.html', **locals())
2) If you want to run Python code in background without any return, you could create a thread.
from threading import Thread
#app.route('/run-in-background')
def run_in_background():
run_func()
return redirect(url_for('.index'))
def run_func():
data = { 'some': 'data', 'any': 'data' }
thr = Thread(target=run_async_func, args=[app, data])
thr.start()
return thr
def run_async_func(app, data):
with app.app_context():
# Your working code here!
example_module.do_somthing_with(data)
Not sure if it helps. Both solutions could make a lot mess.
You should read the flask docs.
The app.config.from_pyfile function evaluates configuration data from Python code. This is very different than your question.

Upload an Image and Display it back as a response using Flask

I'm a beginner in front end development, and have to do a small web app in Flask for a project.
I have written a Flask app that lets you upload an image using HTML Forms and then displays the image back to the user when you hit Upload. I need to modify this such that the image does not get saved to a folder in the project directory everytime a user uploads it. Basically, the app should send the uploaded image back in the body of the response.
Here is my code so far:
UploadTest.py
import os
from uuid import uuid4
from flask import Flask, request, render_template, send_from_directory
app = Flask(__name__)
# app = Flask(__name__, static_folder="images")
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
#app.route("/")
def index():
return render_template("upload.html")
#app.route("/upload", methods=["POST"])
def upload():
target = os.path.join(APP_ROOT, 'images/')
print(target)
if not os.path.isdir(target):
os.mkdir(target)
else:
print("Couldn't create upload directory: {}".format(target))
print(request.files.getlist("file"))
for upload in request.files.getlist("file"):
print(upload)
print("{} is the file name".format(upload.filename))
filename = upload.filename
destination = "/".join([target, filename])
print ("Accept incoming file:", filename)
print ("Save it to:", destination)
upload.save(destination)
return render_template("complete.html", image_name=filename)
#app.route('/upload/<filename>')
def send_image(filename):
return send_from_directory("images", filename)
if __name__ == "__main__":
app.run(port=8080, debug=True)
upload.html - creates an upload form
<!DOCTYPE html>
<html>
<head>
<title>Upload</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
</head>
<body>
<form id="upload-form" action="{{ url_for('upload') }}" method="POST" enctype="multipart/form-data">
<strong>Files:</strong><br>
<input id="file-picker" type="file" name="file" accept="image/*" multiple>
<div id="msg"></div>
<input type="submit" value="Upload!" id="upload-button">
</form>
</body>
<script>
$("#file-picker").change(function(){
var input = document.getElementById('file-picker');
for (var i=0; i<input.files.length; i++)
{
var ext= input.files[i].name.substring(input.files[i].name.lastIndexOf('.')+1).toLowerCase()
if ((ext == 'jpg') || (ext == 'png'))
{
$("#msg").text("Files are supported")
}
else
{
$("#msg").text("Files are NOT supported")
document.getElementById("file-picker").value ="";
}
}
} );
</script>
</html>
complete.html - displays the image from the folder in which it has been saved after a user hits "upload"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
Uploaded
<img src=" {{url_for('send_image', filename=image_name)}}">
</body>
</html>
I have tried researching quite a bit but was unable to find anything other than deleting the folder after it has been displayed (which I didn't think is the right way of solving the question at hand). I'd really appreciate any help in this matter, and if there is a better solution than what my code currently does, I'd love to learn more!
Thank you! :)
Please check below code can help you.Copy the below code in upload.html in templates folder.
<!DOCTYPE html>
<html>
<head>
<link class="jsbin" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.min.js"></script>
<meta charset=utf-8 />
<script src="{{ url_for('static', filename='upload.js') }}"></script>
<style>
article, aside, figure, footer, header, hgroup,
menu, nav, section { display: block; }
</style>
</head>
<body>
<form action = "http://127.0.0.1:5000/uploader" method = "POST"
enctype = "multipart/form-data">
<input type='file' name = 'file' onchange="readURL(this);" />
<img id="blah" src="#" alt="your image" />
<input type = "submit"/>
</form>
</body>
</html>
Copy the below code in upload.js file in static folder
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#blah')
.attr('src', e.target.result)
.width(150)
.height(200);
};
reader.readAsDataURL(input.files[0]);
}
}
Now copy the below code in a python file
from flask import Flask, render_template, request
from werkzeug import secure_filename
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'D:/Projects/flask/image_upload/images/'
#app.route('/')
def upload_f():
return render_template('upload.html')
#app.route('/uploader', methods = ['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
f.save(os.path.join(app.config['UPLOAD_FOLDER'],secure_filename(f.filename)))
return 'file uploaded successfully'
# if __name__ == '__main__':
app.run(debug = True)
Above piece of code will help you to browse and display the image on html page and as well save the image on your disk at desired location.
If you want to send back image to client there's 2 approach,
You can send image to client as an file url
You need to convert an image as blob or base64 image and show image

Categories

Resources