Flask - Empty Files When Uploaded - python

I have a project which allows users to upload files, they will eventually get processed and then serve a result file.
I've just realised, now that I am trying to implement the processing part of the system, that the files are empty when uploaded and I'm not sure where this is going wrong. The files are successfully named and put in the directories, but are empty.
Any help would be much appreciated.
The html form for uploads:
<div class="tile is-vertical is-parent coach" id='fileUploadTile'>
<div class="tile is-child box has-background-light">
<form action='/' method='POST' enctype="multipart/form-data">
<div class='drop-zone'>
<span class='drop-zone__prompt is-family-monospace'>Drag and drop or click here to upload files</span>
<input class="drop-zone__input" type="file" multiple name="uploaded_file" id='fileLoader'>
</div> <!-- end of drop-zone-->
<div class='buttons are-medium' id='fileButtons'>
<input type='submit' class="button is-success is-light is-outlined is-family-monospace" id='submitFiles' value='Process file(s)'>
</form>
<button class='button is-danger is-light is-outlined is-family-monospace' name='resetFiles' id='resetFiles'>Reset File(s)</button>
</div> <!-- end of buttons -->
</div> <!-- end of tile is-child -->
</div> <!-- end of tile is-vertical -->
The code which attempts to validate the files (check extensions, file size, name, etc) and then save:
def file_upload():
if session:
session_name = session.get('public_user')
print("New request from " + str(session_name))
# update when last request was sent
active_sessions[session_name] = datetime.now()
else:
session_token = generate_session_token()
print("Generating new session... " + session_token)
session['public_user'] = session_token # session = key, last request = value
active_sessions[session_token] = datetime.now()
os.mkdir('uploads/'+session['public_user']) #create directory for uploaded files
if request.method == "POST":
if request.files:
files_processed = True
files = request.files.getlist("uploaded_file")
upload_path = app.config['UPLOAD_FOLDER'] + \
str(session['public_user'])
# loop, as possibility of multiple file uploads
for file_to_upload in files:
file_to_upload.seek(0, os.SEEK_END)
file_length = file_to_upload.tell()
file_name = check_existing_file_name(file_to_upload.filename)
# Secures file name against user input
file_name = secure_filename(file_name)
# Checks the file name isn't blank
if file_to_upload.filename == "":
print("Error with file" + file_to_upload.filename +
" - name must not be blank")
files_processed = False
continue
# Checks the file has an allowed extension
elif not allowed_ext(file_to_upload.filename):
print("Error with file" + file_to_upload.filename +
" - extension not supported")
files_processed = False
continue
# Checks file size
elif file_length > app.config['MAX_FILE_SIZE']:
print("Error with file" +
file_to_upload.filename + " file too big")
files_processed = False
continue
else: # Else, passes all validation and is saved.
file_path = upload_path + "/" + file_name
file_to_upload.save(file_path)
# If files have been processed, return a render with success message
if files_processed is True:
return render_template('index.html', is_home='yes', succ="Now processing your files...")
else: # Else, normal redirect.
return redirect(request.url)
else: # If no files request, redirect to index.
return redirect(request.url)
else: # If not a POST request, load page as normal.
return render_template('index.html', is_home='yes')
Sorry if this is something easy or silly I've missed - this is my first project in Python and my first time using Flask.

This all looks pretty ok.
Unrelated: I would do the check for the empty file name against file_name - not file_to_upload.filename.
About your problem:
The only sensible answer could be that with any of your many actions you put the file pointer at the end of the file, and save cannot handle it.
Unfortunately, I have no time to try this on my pc, so please do a seek 0 again - this time just before you call the save method.
I will try this later and update my answer accordingly.
Another way to find out what is going is using a debugger. That is not too complicated.
I made a 5 min video - just for debugging Flask: https://www.youtube.com/watch?v=DB4peJ1Lm2M

I was having the same issue and the recommended fix above helped me! From what I understand it is because you file pointer at the end of the file when you grab the file size. This just has to be undone with another file_to_upload.seek(0).
Just for clarity, your code should now look like:
file_path = upload_path + "/" + file_name
file_to_upload.seek(0)
file_to_upload.save(file_path)

Related

Uploading a text file in Flask and reading it in html

I'm trying to upload a simple text file and then display it in another URL in flask. However, I'm getting a blank output with b" as the only thing showing. Its just a regular text file with utf-8.
Here's the code -
def upload_source():
if request.method == 'POST':
# check if the post request has the file part
f = request.files['file']
if f.filename == "":
print("No file Name")
return redirect(request.url)
if not allowed_file(f.filename):
print("File extension not allowed!")
return redirect(request.url)
else:
full_filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_FOLDER'], full_filename))
print("File saved")
content = f.read()
return render_template('source.html', text=content)
and i'm including this in the source html
<p> {{ text }} </p>
I'm relatively new to python and flask and I appreciate your help here. Thank you!
Thanks to the commenters on this post, I could come up with a fix to this. Initially, I was getting a b" as the only output after using only f.read().
When I used f.seek(0), I got the output of my text file but with a lot of encoding and formatting errors, including a new preceding b` followed by my output.
But adding content = f.read()
content = str(content, 'utf-8') fixed most of that aswell.
So here goes the final solution-
def upload_source():
if request.method == 'POST':
# check if the post request has the file part
f = request.files['file']
if f.filename == "":
print("No file Name")
return redirect(request.url)
if not allowed_file(f.filename):
print("File extension not allowed!")
return redirect(request.url)
else:
full_filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_FOLDER'], full_filename))
f.seek(0)
print("File saved")
content = f.read()
content = str(content, 'utf-8')
return render_template('source.html', text=content)
and don't forget the same old HTML -
<p> {{ text }} </p>
I hope this can help others as well. Thank you!

using flask, send_file a second time to get changed file with same path and name - caching problem?

On our flask website we implemented a "Download" button. This button invokes a function in flask which is providing the user with an zipped file via send_file(). The first time everything works fine. After clicking the button the second time, the user receives the exact same file again. Seems fine, but in the time the button is clicked again, the file that flask should send is changed and the old one is not existing anymore.
I tried to understand why this is happening with the PyCharm Debugger and noticed, that after pressing the download button a second time, the download routine is not even evoked anymore. So I think there is some kind of caching going on in the background. I even deleted the file to be send from the file system and then pressed the Download button a second time... I got the original file back.
Maybe you guys experienced something similar and can help me with your knowledge. Thank you in advance.
The download code:
#app.route('/download/<expID>')
def download(expID):
experiment = dbc.getExperiment(int(expID))
# only execute, if owner of experiment calls it AND experiment is NOT running or in queue
if experiment.getOwner() == cas.username and experiment.getStatus() != 1 and experiment.getStatus() != 2:
ownerPath = dbc.getUser(experiment.getOwner()).getPath()
fileName = cas.username + "_" + expID
# remove old zip (if existing)
try:
os.remove(experiment.getPath() + "/" + fileName + ".zip")
except FileNotFoundError:
pass
# create zip in owner folder to work around recursion problem
make_archive(ownerPath + "/" + fileName, 'zip', root_dir=experiment.getPath(), base_dir=None)
# move from owner folder to owner/experiment folder
shutil.move(ownerPath + "/" + fileName + ".zip", experiment.getPath() + "/" + fileName + ".zip");
# trigger download
return send_file(
experiment.getPath()+"/"+fileName + ".zip", as_attachment=True)
return redirect('/dashboard')
the button:
<form action="/download/{{experiments[i][0]}}">
<input type="submit" id="download" value="download" />
</form>
I found a solution in the documentation of send_file.
Flask indeed caches files that you send via send_file and does not access the function you called previously for a certain amount of time. To limit this behavior you can use the cache_timeout argument. For me it looks like this:
return send_file(
experiment.getPath()+"/"+fileName + ".zip", as_attachment=True, cache_timeout=0)

Download file from Django Project root using a button

So, this is the webpage I'm creating atm with Django 1.8:
Want the user to be able to export the data as .csv.
When the user:
writes a subreddit name in the box
presses the button 'Get Data'
What happens:
it's created a test.csv (saved in the root of the project)
data is retrieved using Praw
data is inserted into the .csv
data is rendered for the users to see
The problem now is:
I want the button with 'Export to Excel', to download the generated file from the root of the Django project.
This is for the button:
<form class="export_excel" id="login_form" action="/app/export">
{% csrf_token %}
<button class="btn btn-lg btn-primary btn-block" value="Export to Excel" type="submit">Export To Excel</button>
</form>
This is in app/views.py:
def export(request):
filename = "test.csv" # this is the file people must download
response['Content-Disposition'] = 'attachment; filename=' + filename
response['Content-Type'] = 'application/vnd.ms-excel; charset=utf-16'
return response
This is in app/urls.py:
# app/urls.py
from django.conf.urls import url
from . import views
# Create your urls here.
urlpatterns = [
(...)
url(r'^export/$', views.export, name='export')
]
This is the error I'm getting when clicking the button:
Question is: How can I make the user export the file using the button? What am I doing wrong?
Thanks in advance for your help / guidance
Handy links:
Link 1
Link 2
Link 3
Link 4
You must first create the response object in order to assign headers to it.
def export(request):
filename = "test.csv" # this is the file people must download
with open(filename, 'rb') as f:
response = HttpResponse(f.read(), content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=' + filename
response['Content-Type'] = 'application/vnd.ms-excel; charset=utf-16'
return response
Taken from here

why doesnt python run the main function?

I am quite a newby with python. I am asking why python does not run the main function in my case. I put a printing function at the beginning of the main function but it never prints. Although I manage to run the rest of the code to create my html upload form on the internet so I do manage to upload files on it. Can you please help?
This part of the code always runs,dont ask me how :(
import web
import csv
urls = ('/upload', 'Upload')
class Upload:
def GET(self):
web.header("Content-Type","text/html; charset=utf-8")
return """<html><head></head><body>
<form method="POST" enctype="multipart/form-data" action="">
<input type="file" name="myfile" />
<br/>
<input type="submit" />
</form>
</body></html>"""
def POST(self):
x = web.input(myfile={})
outfile_errors = open('C:\Python27\csv_results\errors.csv', 'a')
outfile_errors.write("in the post " + "\n " + str(x) + "\n " )
filedir = "C:\Python27\csv_results\\"# change this to the directory you want to store the file in.
if 'myfile' in x: # to check if the file-object is created
filepath=x.myfile.filename.replace('\\','/') # replaces the windows-style slashes with linux ones.
outfile_denumire_fisier = open('C:\Python27\csv_results\denumire_fisier.csv', 'a')
outfile_denumire_fisier.write(filepath + ";" )
outfile_denumire_fisier.close()
filename=filepath.split('/')[-1] # splits the and chooses the last part (the filename with extension)
fout = open(filedir +'/'+ filename,'w') # creates the file where the uploaded file should be stored
fout.write(x.myfile.file.read()) # writes the uploaded file to the newly created file.
fout.close() # closes the file, upload complete.
raise web.seeother('/upload')
#transform()
outfile_errors.close()
This part of the code doesnt work, at least not together with the previous. Separately, it does work.
def transform():
outfile_errors = open('C:\Python27\csv_results\errors.txt', 'a')
outfile_errors.write("in the transform ")
outfile_errors.close()
#bla bla
This is the main, where i put a printing-to-file function that never works, although somehow the program runs the first function and generates my html format and allows me to upload files like i want. strange, right?
if __name__ == "__main__":
outfile_errors = open('C:\Python27\csv_results\errors.csv', 'a')
outfile_errors.write("in the main beginning" + "\n " )
app = web.application(urls, globals())
app.run()
outfile_errors.write("in the main middle" + "\n " )
transform()
outfile_errors.write("in the main end " + "\n " )
outfile_errors.close()
Can you please help?
you are not telling the program to write to the correct variable. Change outfile.write to Outfile_errors.write in the second half of your main fucntion

Error with web.py uploading <type 'exceptions.IOError'>

So i am following the web.py uploading and storing guide to test it out but i keep geting a
error stating that [Errno 2] No such file or directory :< help
this is my code
import web
urls = (
'/hello', 'index',
'/hello/upload', 'upload'
)
app = web.application(urls, globals()) # handels http request that aks for urls
# the base ells lpthw.web to use the templates/layout.html file as the base template for all the other templates
render = web.template.render('templates/', base="layout")
# must use port 127.0.0.1:5000
class index(object):
def GET(self):
return render.hello_form()
def POST(self):
form = web.input(name="Nobody", greet="Hello")
greeting = "%s, %s" % (form.greet, form.name)
return render.index(greeting = greeting)
class upload(object):
def POST(self):
x = web.input(files={})
filedir = '/project/webtest/templates' # directory were you want to save the file
if 'files' in x: # check if the file -object is created
filepath=x.files.filename.replace('\\','/') # replace the windows -style slashes with linux ones
filename=filepath.split('/')[-1] #splits the and chooses the last part (the filename with extension
fout = open(filedir +'/'+ filename,'w') # creates the file where the uploaded file should be stored
fout.write(x.files.file.read()) #writes the uploaded file to the newly created file.
fout.close() #closes the file
else:
return "Error no file"
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
help thx
import web
urls = ('/upload', 'Upload')
class Upload:
def GET(self):
web.header("Content-Type","text/html; charset=utf-8")
return view.upload()
def POST(self):
x = web.input(myfile={})
filedir = '/path/where/you/want/to/save' # change this to the directory you want to store the file in.
if 'myfile' in x: # to check if the file-object is created
filepath=x.myfile.filename.replace('\\','/')
filename=filepath.split('/')[-1]
fout = open(filedir +'/'+ filename,'w')
fout.write(x.myfile.file.read()) # writes the uploaded file to the newly created file.
fout.close() # closes the file, upload complete.
raise web.seeother('/upload')
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
upload.html
<html>
<head>
<title>File upload</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data" action="">
<input type="file" name="myfile" /><br/>
<input type="submit" />
</form>
</body>
</html>
for your reference http://webpy.org/cookbook/storeupload/
I met the same problem myself, and tried to ask that here. But nobody answers.
Finally, I figured it out what's the problem and would like to share with you!
This part: filedir = '/project/webtest/templates' should be an absolute path.
And it should be an existing directory (at least in my trail it should be an existing directory, otherwise it would prompt the same error as you posted)! The file need not to be exciting since we are going to create it by copying the uploaded file.
For example in my mac, it's '/Users/J/pythonex/projects/gothonweb/docs', and it's an existing directory. If it's not an existing directory, you will get the same error message.
Last, the most tricky part. Im my mac, the uploaded files are actually stored in my disk in that exact directory. But I can't see them in my finder until I relaunch the finder. I don't know why is that. But for my computer, that's the case.

Categories

Resources