How to get file name from uploads via put request - python

I am developing API using Flask-restplus. One of the endpoints handles audio file uploads which can be either mp3 or wav format. According to PUT request to upload a file not working in Flask, file uploaded by put is in either request.data or request.stream. So this is what I did:
#ns.route('/upload')
class AudioUpload(Resource):
def put(self):
now = datetime.now()
filename = now.strftime("%Y%m%d_%H%M%S") + ".mp3"
cwd = os.getcwd()
filepath = os.path.join(cwd, filename)
with open(filepath, 'wb') as f:
f.write(request.stream.read())
return filepath
I am saving the file as mp3. However sometime the file comes in as wav. Is there a way to get the original file name from put request in the similar way as post request:
file = request.files['file']
filename = file.filename

Related

Django: download created zip from function. Zipfile returns empty/not an zip-archive file

I am trying to give the user a "Save as" option when the user clicks the download button in my Django app. When the user clicks the button it kicks-off the following function. The function gets some CSVs from a blob container in Azure and adds them to a zip. That zip should then be offered to download and store in a location of the user's choice.
def create_downloadable_zip():
container_client = az.container_client(container_name=blob_generator.container_name)
blobs = container_client.list_blobs()
zip_file = zipfile.ZipFile(f'{models.AppRun.client_name}.zip', 'w')
for blob in blobs:
if blob.name.endswith(".csv"):
downloaded_blob = container_client.download_blob(blob)
blob_data = downloaded_blob.readall()
zip_file.writestr(blob.name, blob_data)
zip_file.close()
return zip_file
My views.py looks like follow:
def download_file(request):
if request.method == 'POST':
zip = create_downloadable_zip()
response = HttpResponse(zip, content_type='application/zip')
response['Content-Disposition'] = 'attachement;' f'filename={zip}.zip'
return response
#
# else:
# # return a 404 response if this is a POST request
# return HttpResponse(status=404)
return render(request, "download_file.html")
The functionality works, but it returns an empty non-zip file when the "Save as" window pop-ups. However, the actual zip file contains the files is being saved in the root folder of the Django project.
I really don't get why I doesn't return the zip file from memory, but rather directly stores that zip file in root and returns an empty non-zip file with the download functionality.
Someone knows what I am doing wrong?
zipfile is used to open a file, but it is not the actual file, simply a zipfile object as #b-remmelzwaal mentioned. You will need to create a file like object, and return that instead. This can be done using io.BytesIO.
from io import BytesIO
from zipfile import ZipFile
def create_zip():
container_client = az.container_client(container_name=blob_generator.container_name)
blobs = container_client.list_blobs()
buffer = BytesIO()
with ZipFile(buffer, 'w') as zip_file:
for blob in blobs:
if blob.name.endswith(".csv"):
downloaded_blob = container_client.download_blob(blob)
blob_data = downloaded_blob.readall()
zip_file.writestr(blob.name, blob_data)
return buffer.getvalue()
Note we are returning the file like object, not the zip file object. This is because buffer represents the actual file you've created.
You don't have to use a context manager, but I find them very useful.
Also, check your spelling for the line:
# attachment instead attachement
response['Content-Disposition'] = 'attachment;' f'filename={zip}.zip'
BytesIO Documentation

Django: How do I download .xls file through a django view

I have a button which downloads a excel file with extension .xls. I am using module xlrd to parse the file and return it back to the user. However it appears to add the object name into the excel file instead of the data.
How can I return the file to the user with the data rather than the objects name?
View
def download_file(self, testname):
import csv, socket, os, xlrd
extension = '.xls'
path = r"C:\tests\{}_Report{}".format(testname, extension)
try:
f = xlrd.open_workbook(path)
response = HttpResponse(f, content_type='application/ms-excel')
response['Content-Disposition'] = 'attachment; filename={}_Report{}'.format(testname, extension)
return response
except Exception as Error:
return HttpResponse(Error)
return redirect('emissions_dashboard:overview_view_record')
Excel result
Download successful:
Content:
Note: I understand this is an old file format but is required for this particular project.
You are trying to send a xlrd.book.Book object, not a file.
You used xlrd to do your things in the workbook, and then saved to a file.
workbook = xlrd.open_workbook(path)
#... do something
workbook.save(path)
Now you send it like any other file:
with open(path, 'rb') as f:
response = HttpResponse(f.read(), content_type="application/ms-excel")
response['Content-Disposition'] = 'attachment; filename={}_Report{}'.format(testname, extension)

Download zip file with Django

I'm quite new on Django and i'm looking for a way to dwonload a zip file from my django site but i have some issue when i'm running this piece of code:
def download(self):
dirName = settings.DEBUG_FOLDER
name = 'test.zip'
with ZipFile(name, 'w') as zipObj:
# Iterate over all the files in directory
for folderName, subfolders, filenames in os.walk(dirName):
for filename in filenames:
# create complete filepath of file in directory
filePath = os.path.join(folderName, filename)
# Add file to zip
zipObj.write(filePath, basename(filePath))
path_to_file = 'http://' + sys.argv[-1] + '/' + name
resp= {}
# Grab ZIP file from in-memory, make response with correct MIME-type
resp = HttpResponse(content_type='application/zip')
# ..and correct content-disposition
resp['Content-Disposition'] = 'attachment; filename=%s' % smart_str(name)
resp['X-Sendfile'] = smart_str(path_to_file)
return resp
I get:
Exception Value:
<HttpResponse status_code=200, "application/zip"> is not JSON serializable
I tried to change the content_type to octet-stream but it doesn't work
And to use a wrapper as followw:
wrapper = FileWrapper(open('test.zip', 'rb'))
content_type = 'application/zip'
content_disposition = 'attachment; filename=name'
# Grab ZIP file from in-memory, make response with correct MIME-type
resp = HttpResponse(wrapper, content_type=content_type)
# ..and correct content-disposition
resp['Content-Disposition'] = content_disposition
I didn't find useful answer so far but maybe I didn't search well, so if it seems my problem had been already traited, feel free to notify me
Thank you very much for any help
You have to send the zip file as byte
response = HttpResponse(zipObj.read(), content_type="application/zip")
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(name)
return response
I would do like this:
(Caveat I use wsl so the python function will make use of cmd lines)
In view:
import os
def zipdownfun(request):
""" Please establish in settings.py where media file should be downloaded from.
In my case is media with a series of other folders inside. Media folder is at the same level of project root folder, where settings.py is"""
file_name = os.path.join(MEDIA_URL,'folder_where_your_file_is','file_name.zip')
"""let us put the case that you have zip folder in media folder"""
file_folder_path = os.path.join(MEDIA_URL,'saving_folder')
"""The command line takes as first variable the name of the
future zip file and as second variable the destination folder"""
cmd = f'zip {file_name} {file_folder_path}'
"""With os I open a process in the background so that some magic
happens"""
os.system(cmd)
"""I don't know what you want to do with this, but I placed the
URL of the file in a button for the download, so you will need
the string of the URL to place in href of an <a> element"""
return render(request,'your_html_file.html', {'url':file_name})
The db I have created, will be updated very often. I used a slightly different version of this function with -r clause since I had to zip, each time, a folder. Why I did this? The database I have created has to allow the download of this zipped folder. This folder will be updated daily. So this function basically overwrites the file each time that is downloaded. It will be so fresh of new data each time.
Please refer to this page to understand how to create a button for the download of the generated file.
Take as reference approach 2. The URL variable that you are passing to the Django template should be used at the place of the file (screenshot attached)
I hope it can help!

Generate and upload a file to s3 with flask

is it possible to generate and upload a file to s3?
I have tried to implement this flask application, but it dies with this error:
OSError: [Errno 30] Read-only file system: '/report.csv'
This is my app.py:
#app.route("/upload/<string:START_REPORT>/<string:STOP_REPORT>/<string:IDS>/", methods=['POST'])
def upload(START_REPORT, STOP_REPORT, IDS):
"""
Function to upload a file to an S3 bucket
"""
os.environ["START_REPORT"] = START_REPORT
os.environ["STOP_REPORT"] = STOP_REPORT
os.environ["IDS"] = IDS
dft, filename = report_visit.report()
dft.to_csv(filename, index=False) # <-- Error here
object_name = filename
s3_client = boto3.client(
"s3",
region_name='eu-west-1',
endpoint_url="url",
aws_access_key_id="key",
aws_secret_access_key="key"
)
with open(filename, "rb") as f:
response = s3_client.upload_fileobj(f, app.config['UPLOAD_FOLDER'], f.filename)
return response
if __name__ == '__main__':
app.run (debug=True, port='8080', host='127.0.0.1')
where filename is 'report.csv'
This is the post request I do with postman:
POST http://localhost:8080/upload/2020_2_10_0_0_0_0/2020_2_10_1_0_0_0/138/
It would be hard I think for me to give a proper working example, but any suggestion are welcome
the function report_visit.report() returns a pandas dataframe and the name of the filename
Any suggestion would be appreciated, thanks
Matteo
You are trying to write into the root directory '/'. So, your app needs root permissions (run with sudo; highly not recommended by security thoughts) or specify some path to tmp folder to store those files there(looks like you want to use "./report.csv" - file will be created into working directory).

Read text file from input type file

I have from and in the form the user can upload files.
I'm using flask, and what im trying to do is to get the data from the text file that the user choose to upload.
There is any way to read the data inside the text file?
I have tried to open the file file = open(), but then i realized that i dont have the path.
Its diffrent then reading file on your local machine.
#app.route('/admin',methods=['GET','POST'])
def admin_panel():
if request.method == 'GET':
return render_template('adminpanel.html')
if request.method == 'POST':
email = request.form['email']
file_data = request.files['file']
file_name = secure_filename(file_data.filename)
file_data.save(os.path.join("system","files","text",file_name))
with open("system/files/text/file_name") as f:
file_content = f.read()
print(file_content)
file = File(file_data)
file.read_file_dif()
Well of course this code does not working. But thats the idea.
Anyone have any idea how i can read a text file from an input file tag?
HTML TAG
<label for="myfile">Select a file:</label>
<input type="file" id="myfile" name="file">
The best way to approach is first saving the file and then reading it to get the text. As a convention, you set a UPLOAD_FOLDER variable with the path to save. Then, in flask use the following to save the file:
file_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename))
f = request.files['file']
f.save(file_path)
# This would save the file. Now to read simply use the normal way to read files in Python
with open(file_path, 'r') as f:
file_content = f.read()
# Rest of the processing logic
Note that the path is relative to your current working directory, which is usually the root of your project. Also, please be careful when storing and reading files from untrusted users.
A better place to store these files would be somewhere other than your project root. You could have a data directory somewhere through which you could configure Nginx (or any other front proxy) to serve the uploaded files
This is my solution to my problem
from werkzeug.utils import secure_filename
import os
class File():
def __init__(self,file):
self.file = file
def read_file(self):
file_name = secure_filename(self.file.filename)
self.file.save(os.path.join("app", "static", file_name))
with open(f"app/static/{file_name}") as f:
email_list = f.read().splitlines()
return email_list

Categories

Resources