flask send_from_directory function keeps sending the same old file - flask

I have a flask app that contains a link to download a file from the server. The file will be updated by another callback function. The part for send_from_directory is like this:
app = flask.Flask(__name__)
dash_app = dash.Dash(__name__,server=app,url_base_pathname="/",external_stylesheets=external_stylesheets)
...
#dash_app.server.route('/download/',methods=["GET","POST"])
def download_data():
return flask.send_from_directory("../data/",
filename='result.csv',
as_attachment=True,
attachment_filename='result.csv',
cache_timeout=0)
I have 2 problems:
1) the file downloaded are always the same old file, despite I have have set the cache timeout as 0.
2) the downloaded file are always named as "download", instead of the file name I specified "result.csv".

Related

Accessing Goaccess report.html within flask

I have a website that uses flask and I would like to display the stats generated by goaccess from within my website.
in my route.py, I have added:
#main.route("/report")
def report():
return render_template('report.html')
and I have made sure the report.html is in the template forlder.
the problem is that I get the following error:
File "/templates/report.html", line 866, in template
<div class="grid-module {{#className}}{{className}}{{/className}}{{^className}}gray{{/className}}">
File "/lib/python3.6/site-packages/jinja2/environment.py", line 497, in _parse
return Parser(self, source, name, encode_filename(filename)).parse()
File "/lib/python3.6/site-packages/jinja2/parser.py", line 901, in parse
result = nodes.Template(self.subparse(), lineno=1)
File "/lib/python3.6/site-packages/jinja2/parser.py", line 874, in subparse
next(self.stream)
File "/lib/python3.6/site-packages/jinja2/lexer.py", line 359, in __next__
self.current = next(self._iter)
File "/lib/python3.6/site-packages/jinja2/lexer.py", line 562, in wrap
for lineno, token, value in stream:
File "/lib/python3.6/site-packages/jinja2/lexer.py", line 739, in tokeniter
name, filename)
jinja2.exceptions.TemplateSyntaxError: unexpected char '#' at 298804
Would anyone know how to solve this? I don't want to touch report.html and would like to use it as such.
If there is no solutions, can anyone suggest a way to access report.html from the internet?
Thank you.
What you want to do is serve a static file using flask. See How to serve static files in Flask
If you take a look at the docs the render_template function "Renders a template from the template folder with the given context". What you have is a complete, self-contained HTML file, and not a template. You could instad use the send_from_directory function. Do note that in production environment you probably do not want to serve file using Flask but instead use the web server (e.g. NGINX).
Example code:
from pathlib import Path
import os
...
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
TEMPLATES_DIR = os.path.join(APP_ROOT, 'templates')
#app.route("/report")
def report():
REPORT_FILE = os.path.join(TEMPLATES_DIR, "report.html")
if Path(REPORT_FILE).is_file():
return send_from_directory(REPORT_FILE_PATH, "report.html")
return "No stats."

Read Excel file from Memory in Django

I am trying to read an excel file from memory in django but keep getting the following error:
NotImplementedError: formatting_info=True not yet implemented
Here's the code:
from pyexcel_xls import get_data
def processdocument(file):
print("file", file)
data = get_data(file)
return 1
when I am reading the same file from the local storage it works perfectly
data = get_data(r"C:\Users\Rahul Sharma\Downloads\Sample PFEP (2).xlsx")
I had a workaound solution in mind i.e. to save the uploaded file temporary in django os and then pass its URL to the function.
Can I do that?

Django FileResponse - How to speed up file download

I have a setup that lets users download files that are stored in the DB as BYTEA data. Everything works OK, except the download speed is very slow...it seems to download in 33KB chunks, one chunk per second.
Is there a setting I can specify to speed this up?
views.py
from django.http import FileResponse
def getFileResponse(filedata, filename, filesize, contenttype):
response = FileResponse(filedata, content_type=contenttype)
response['Content-Disposition'] = 'attachment; filename=%s' % filename
response['Content-Length'] = filesize
return response
return getFileResponse(
filedata = myfile.filedata, # Binary data from DB
filename = myfile.filename + myfile.fileextension,
filesize = myfile.filesize,
contenttype = myfile.filetype
)
Previously, I had the binary data returned as an HttpResponse and it downloaded like a normal file, with normal speeds. This worked fine locally, but when I pushed to Heroku, it wouldn't download the file -- instead displaying <Memory at XXX> in the download file.
And another side issue...when I include a text file with non-ASCII data (i.e. รก), I get an error as well:
UnicodeEncodeError: 'ascii' codec can't encode characters...: ordinal not in range(128)
How can I handle files with Unicode data?
Update
Anyone know why the download speed gets so slow when changing from HTTPResponse to FileResponse? Or alternatively, why the HTTPResponse to return a file doesn't work on Heroku?
Update - Google Drive
I re-worked my application and hooked it up with a Google Drive back-end for serving files. It employs BytesIO() suggested by Eric below:
def download_file(self, fileid, mimetype=None):
# Get binary file data
request = self.get_file(fileid=fileid, mediaflag=True)
stream = io.BytesIO()
downloader = MediaIoBaseDownload(stream, request)
done = False
# Retry if we received HTTPError
for retry in range(0, 5):
try:
while done is False:
status, done = downloader.next_chunk()
print("Download %d%%." % int(status.progress() * 100))
return stream.getvalue()
except (HTTPError) as error:
return ('API error: {}. Try # {} failed.'.format(error.response, retry))
I think the difference you observe between HttpResponse vs. FileResponse is caused by the spec: https://www.python.org/dev/peps/pep-3333/#buffering-and-streaming
In your previous code, an HttpResponse was created with one huge byte string containing your whole file, and the first iteration pass returned the complete response body. With a a FileResponse, the file is iterated in chunks (of 4kb, 8kb or other depending on your WSGI app server), which (I think) are streamed immediately upstream (to the reverse proxy then client), which may add overhead (more communication over process boundaries?).
It would help to know the app server used (uwsgi, gunicorn, waitress, other) and its relevant config. Also more details about the heroku error in case that can be solved!
why you store whole file in database.
best case is to store file on hard and store only path on database
then according to your web server you can let web server to serve file.
web services serve file better than Django.
if files have no access check store them on media
if your files have access control you according to your web server you can use some response headers
if you use Nginx must use X-Accel-Redirect and use any alternative on other web services tutorial on https://wellfire.co/learn/nginx-django-x-accel-redirects/

Python read a file in zip archives from api call

I have a restful endpoint which my rest api could make a get request to it and the file is a zip file. In this zip file, there're 2 files. I only want to read the content in 1 file from this zip archives. I was able to do a test and it likes my code stuck on line file=zipfile.ZipFile(io.BytesIO(response_object.content)).
class ZipFileResponseHandler:
def __init__(self,**args):
self.csv_file_to_index = args['csv_file_to_index']
def __call__(self, response_object, raw_response_output, response_type, req_args, endpoint):
file = zipfile.ZipFile(io.BytesIO(response_object.content))
for name in file.namelist():
if re.match(name, self.csv_file_to_index):
data =file.read(name)
print_xml_stream(repr(data))
So i found the solution to my own answer. Because I use python 2.7 the corresponding method that use to handle the response_object is StringIO not BytesIO. So the line:
file = zipfile.ZipFile(io.BytesIO(response_object.content))
should be
file = zipfile.ZipFile(StringIO.StringIO(response_object.content))

Upload an mp3 files to soundcloud using Python (file name is random)

I'd like to upload an mp3 file from hotfolder without knowing the name of the file. (such as *.mp3)
here's what I tried (to upload specific file / known file name)
import soundcloud
# create client object with app and user credentials
client = soundcloud.Client(client_id='***',
client_secret='***',
username='***',
password='***')
# print authenticated user's username
print client.get('/me').username
mp3_file=('test.mp3')
# upload audio file
track = client.post('/tracks', track={
'title': 'Test Sound',
'asset_data': open(mp3_file, 'rb')
})
# print track link
print track.permalink_url
how can I make the script upload any mp3 file in that folder ? (script and files are located in the same folder)
From the language as written here, it's not precisely clear what you mean by "upload any mp3 file in that folder." Does uploading the first file in the folder satisfy your need, or does it need to be a different file each time the script executes? If the latter, my suggestion is to get a list of files and then randomly select one of them.
To get a list of all files in python,
from os import listdir
from os.path import isfile, join
onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]
and then to randomly select one of them:
import random
print(random.choice(onlyfiles))
Hope this helps