web.py file upload using the built in File form - python

I'm trying to make a working file upload form using the built in input form. It works just fine with a 'static' html input form (using shutil.copyfileobject), but it won't work using the built in one.
import web, shutil
from web import form
urls = ('/', 'Index')
app = web.application(urls, globals())
render = web.template.render('templates/')
fileForm = form.Form(form.File('myfile'))
class Index(object):
def GET(self):
f = fileForm()
return render.index(f)
def POST(self):
f = fileForm()
fi = f['myfile']
mydir = 'uploads/'
shutil.copy(fi, mydir)
if __name__ == "__main__":
app.run()
And templates/index.html
$def with (f)
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
<form name="main" method="post" enctype="multipart/form-data" action="">
$:f.render()
<input type="submit">
</form>
</body>
</html>
Errors:
<type 'exceptions.TypeError'> at /
coercing to Unicode: need string or buffer, File found
Python
C:\Python27\lib\ntpath.py in abspath, line 486
Web
POST http://localhost:8080/
Traceback (innermost first)
C:\Python27\lib\ntpath.py in abspath
479.
480.else: # use native Windows method on Windows
481. def abspath(path):
482. """Return the absolute version of a path."""
483.
484. if path: # Empty path must return current working directory.
485. try:
486. path = _getfullpathname(path) ...
487. except WindowsError:
488. pass # Bad path - return unchanged.
489. elif isinstance(path, unicode):
490. path = os.getcwdu()
491. else:
492. path = os.getcwd()
The built in File doesn't seem to return an object, so shutil.copyfileobject does not seem to work.
Please help me sort it out.

import web, shutil
from web import form
urls = ('/', 'Index')
app = web.application(urls, globals())
render = web.template.render('templates/')
fileForm = form.Form(form.File('myfile'))
class Index(object):
def GET(self):
f = fileForm()
return render.index(f)
def POST(self):
x = web.input(myfile={})
filedir = '/tmp/'
if 'myfile' in x:
filepath=x.myfile.filename.replace('\\','/')
filename=filepath.split('/')[-1]
fout = open(filedir +'/'+ filename,'w')
fout.write(x.myfile.file.read())
fout.close()
if __name__ == "__main__":
app.run()

Related

User-specific download file in django

i have an app in django that do some processes and build a file, in one section, i want to show the user that file to download that.
(for example, user enter a name in front-end and the app give him a pdf file to download).
the file building process is ok and it is in /app_dir/media/app/report/username/file.pdf
here is my code, but it does not worked and i faced some problems.
can you please help me, where is my problem?
and how i can make that user-specefic? each user just can access to his files.
views.py (my_main_function):
#login_required(login_url='/login/')
def my_function(request):
if request.method == 'GET':
return render(request, 'app/my_function.html')
else:
try:
#my main process to build .PDF file
except ValueError:
return render(request, 'app/dashboard.html', {'error':'Bad data passed in. Try again.'})
return render(request, 'app/download.html')
views.py (download function):
def download_file(request):
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
filename = f"{file}.pdf"
# Define the full file path
filepath = f"{BASE_DIR}/app/media/app/reports/{user_name}/{filename}"
# Open the file for reading content
path = open(filepath, 'rb')
path.read()
# Set the return value of the HttpResponse
response = HttpResponse(path, content_type='application/pdf')
# Set the HTTP header for sending to browser
response['Content-Disposition'] = "attachment; filename=%s" % filepath
# Return the response value
return response
urls.py:
path('download/', views.download_file, name='download_file'),
simple testing download.html file:
<html>
<title>Download File</title>
</head>
<body>
<enter>
<h1>Download File using link</h1>
Download PDF
</center>
</body>
</html>
It is not clear what problems you have encountered, but there are some lines I would correct in your code
# first of all why not use django.http.FileResponse instead of HttpResponse?
# https://docs.djangoproject.com/en/3.2/ref/request-response/#fileresponse-objects
from django.http import FileResponse
# if you want files to be accessible only to owners
# you probably should force user to login before download
#login_required
def download_file(request):
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
filename = f"{file}.pdf"
filepath = f"{BASE_DIR}/app/media/app/reports/{user_name}/{filename}"
# somewhere here you need to check if user has access to the file
# if files ownership based solely on {user_name} dir in filesystem
# then it is enough to check if file exists
if os.path.exists(filepath):
response = FileResponse(open(filepath, 'rb'))
# it is probably better to use filename instead of filepath
response['Content-Disposition'] = "attachment; filename=%s" % filename
return response
else:
raise Http404

How to update image in real time with flask?

I am using flask (python) to host a interface that allows the user to upload an image, and use a slider to change the value of a variable in a function that reduces noise in an image.
The slider works but the problem is I have to reload the page every time that I want to see the change in value on the updated image.
how can I add a slider that will update the image in real time so I won't have to continuously reload the page to see the changes?
(If the slider is at 0 I want it to to look how the image did when it first uploaded)
I'm doing some searching and it looks like I would use jquery or something but I don't know how to implement it
thanks for reading
app.py:
import os
from flask import Flask, render_template, request, send_from_directory,url_for, session, redirect
import cv2
import shutil
app = Flask(__name__)
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
app.config['UPLOAD_FOLDER'] = os.path.join(APP_ROOT, 'images')
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
#app.route("/")
def index():
session.clear()
return render_template("upload.html")
#app.route('/images/<filename>')
def uploadfile(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],filename)
#app.route('/home')
def home():
return render_template("completed.html", imgSrc="images/" + session.get('imgSrc') , message=session.get('message'))
#app.route("/upload" , methods = ['POST'])
def upload():
target = os.path.join(APP_ROOT, 'images')
if request.method == 'POST':
if not os.path.isdir(target):
os.mkdir(target)
for file in request.files.getlist("file"):
filename = file.filename
destination = "/".join((target, filename))
file.save(destination)
filename = destination
org = open(filename, 'rb')
base = os.path.basename(filename)
dir = os.path.dirname(filename)
filename_cp = os.path.splitext(base)[0]
filename_cp = "cp_"+filename_cp+os.path.splitext(base)[1]
destination2 = dir+"/"+filename_cp
file.save(destination2)
cpy = open (destination2, 'wb')
shutil.copyfileobj(org, cpy)
session['image'] = filename
session['filename'] = filename
session['imgSrc'] = os.path.basename(destination)
session['cimgsrc'] = os.path.basename(destination2)
session['cpimg'] = destination2
print("session", session)
return render_template("completed.html",imgSrc="images/"+session.get('imgSrc'))
#app.route("/imgp/nr", methods=['post'])
def nr():
print(session)
img = cv2.imread(session.get('cpimg'), 0)
#threshold = 40
threshold = float(request.form['slider'])
cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY, img)
print (session['cpimg'])
cv2.imwrite(session.get('cpimg'),img)
session['message'] = "NR is done!"
session['imgSrc'] = os.path.basename(session['cpimg'])
return redirect(url_for('home', op='nr'))
if __name__ =="__main__":
app.secret_key = "abcdefghijklmnopqrstuvwxyz"
app.run(port = 4555, debug = True)
upload.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Upload</title>
</head>
<form id ="upload-form" action="{{ url_for ('upload') }}" method = "POST" enctype="multipart/form-data">
<input type="file" name="file" accept = image/* multiple>
<p>Drag your files here or click in this area.</p>
<button type ="submit" value="Upload"> Upload</button>
</form>
<body>
</body>
</html>
completed.hmtl (where the slider and uploaded image is):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1> file uploaded</h1>
<img src="{{imgSrc}}" style="height:200px;width:300px;"/>
<h2>{{message}}</h2>
<form action ="imgp/nr" method = "post">
<input type="range" min={{min}} max={{max}} value={{max}} class="slider" id="myRange" name="slider">
<input type="submit" value="Apply ga">
</form>
</body>
</html>
The short answer is you will need to do this with Javascript/jQuery. There's a similar question here covers two ways to do it:
Either load the (base64 converted) image via ajax; or
Change the src of the image on the page using jquery, to have it reload.
You will likely need to change a few parts of your code to get this all working, but it may be something along the lines of:
app.py:
Change your nr() function to GET, and return a base64 encoded image, see here for example (upload_file() function)
completed.html:
Add an ajax (the following is jquery) call to /imgp/nr that changes the display of the image on the page, when the slider is changed. For example:
...
<img id="yourImage" style="height:200px;width:300px;">
...
<script type="text/javascript">
$("#myRange").change(function(){
var sliderVal = $(this).val();
$.ajax({
medthod: 'POST',
url:'/imgp/nr/',
data: JSON.stringify({slider: sliderVal}),
success: function(data){
$("#yourImage").attr('src', 'data:image/png;base64, ' + data);
}
});
});
</script>
This code may need some fixing, I don't have much time to make it perfect sorry. Hopefully you get the idea!

Convert normal Python script to REST API

Here I have an excel to pdf conversion script. How can I modify it to act as a REST API?
import os
import comtypes.client
SOURCE_DIR = 'D:/projects/python'
TARGET_DIR = 'D:/projects/python'
app = comtypes.client.CreateObject('Excel.Application')
app.Visible = False
infile = os.path.join(os.path.abspath(SOURCE_DIR), 'ratesheet.xlsx')
outfile = os.path.join(os.path.abspath(TARGET_DIR), 'ratesheet.pdf')
doc = app.Workbooks.Open(infile)
doc.ExportAsFixedFormat(0, outfile, 1, 0)
doc.Close()
app.Quit()
You can use Python's Flask lightweight Rest Framework to make your program accessible for REST Calls. Check this tutorial: http://flask.pocoo.org/docs/1.0/tutorial/
There you can simply get the file input in POST format and once the file is converted send a downloadable link to the end user. You have to tweak this code I wrote with a friend for similar purposes:
import os
from flask import Flask, request, redirect, url_for
from werkzeug import secure_filename
PROJECT_HOME = os.path.dirname(os.path.realpath(__file__))
UPLOAD_FOLDER = '{}/uploads/'.format(PROJECT_HOME)
ALLOWED_EXTENSIONS = set(['txt','pdf', 'vcf'])
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 index():
if request.method == 'POST':
file = request.files['file']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
_path = os.path.abspath("<FILE PATH>")
uf = str(uuid.uuid4())
# DO YOUR AMAZING STUFF HERE
return redirect(url_for('index'))
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>
<p>%s</p>
""" % "<br>".join(os.listdir(app.config['UPLOAD_FOLDER'],))
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5001, debug=True)

flask: `#after_this_request` not working

I want to delete a file after the user downloaded a file which was created by the flask app.
For doing so I found this answer on SO which did not work as expected and raised an error telling that after_this_request is not defined.
Due to that I had a deeper look into Flask's documentation providing a sample snippet about how to use that method. So, I extended my code by defining a after_this_request function as shown in the sample snippet.
Executing the code resp. running the server works as expected. However, the file is not removed because #after_this_request is not called which is obvious since After request ... is not printed to Flask's output in the terminal:
#!/usr/bin/env python3
# coding: utf-8
import os
from operator import itemgetter
from flask import Flask, request, redirect, url_for, send_from_directory, g
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = '.'
ALLOWED_EXTENSIONS = set(['csv', 'xlsx', 'xls'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
def after_this_request(func):
if not hasattr(g, 'call_after_request'):
g.call_after_request = []
g.call_after_request.append(func)
return func
#app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
#after_this_request
def remove_file(response):
print('After request ...')
os.remove(filepath)
return response
return send_from_directory('.', filename=filepath, as_attachment=True)
return '''
<!doctype html>
<title>Upload a file</title>
<h1>Uplaod new file</h1>
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
'''
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
What do I miss here? How can I ensure calling the function following to the #after_this_request decorator in order to delete the file after it was downloaded by the user?
Note: Using Flask version 0.11.1
Just import after_this_request from flask, you don't need to modify after_request or create a hook.
from flask import after_this_request
#after_this_request
def remove_file(response):
print('After request ...')
os.remove(filepath)
return response
Make sure to import the decorator from flask.after_this_request. The decorator is new in Flask 0.9.
If you are using Flask 0.8 or older, then there is no specific after this request functionality. There is only a after every request hook, which is what the snippet coopts to handle per-request call-backs.
So unless you are using Flask 0.9 or newer you need to implement the documented hook yourself:
#app.after_request
def per_request_callbacks(response):
for func in getattr(g, 'call_after_request', ()):
response = func(response)
return response
So that hook is run after each and every request, and looks for a list of hooks to call in g.call_after_request. The after_this_request decorator registers a function there.

upload image flask error

I'm following the Flask tutorial for image uploading. I also decided to tinker with it a bit so that I can add other features. The website loads locally, but when I actually click on the upload button (after selecting a .png image), I get the following error:
Bad Request. The browser (or proxy) sent a request that this server could not understand.
I've read something about adding an else statement here:
Form sending error, Flask
But I'm not sure how to accommodate it for my needs.
Here is my code:
from flask import Flask, request, session, g, redirect, url_for, \
abort, render_template, flash
from werkzeug import secure_filename
import os
DEBUG = True
SECRET_KEY = 'development key'
USERNAME = 'admin'
PASSWORD = 'default'
#Add parameters for image uploads:
UPLOAD_FOLDER = '/upload_folder/'
ALLOWED_EXTENSIONS = set(['png','jpg','jpeg'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
##app.route('/')
##app.route('/<name>')
#Image uploads:
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':
file = request.files['file']
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('uploaded_file',filename=filename))
return '''
<!doctype html>
<title>Upload new File</title>
<h1>UPload new File</h1>
<form action="" method=post enctype=multpart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
'''
#Handle errors:
#app.errorhandler(404)
def page_not_found(error):
return render_template('page_not_found.html'),404
#render template:
def flaskr(name=None):
return render_template('hello.html',name=name)
#Handle errors:
#app.errorhandler(404)
def page_not_found(error):
return render_template('page_not_found.html'),404
if __name__ == '__main__':
app.run()
There is a typo in your html code:
<form action="" method=post enctype=multpart/form-data>
should be multipart and not multpart.

Categories

Resources