I am generating a xlsx file which I would like to download once it is created. The file is created using a module called 'xlsxwriter'. It saves the file in my root directory, however I cant figure out how to access it via flask, so that it starts a download.
This is how I create the file:
workbook = xlsxwriter.Workbook('images.xlsx')
worksheet = workbook.add_worksheet()
worksheet.write(..someData..)
It saves the file in my root directory.
Now I am trying to access it in order to download it via flask:
app = Flask(__name__, static_url_path='')
#app.route('/download')
def download():
# do some stuff
return Response(
app.send_static_file('images.xlsx'),
mimetype="xlsx",
headers={"Content-disposition":
"attachment; filename=images.xlsx"})
However, I get a 404 Error. Is using send_static_file the correct way to go here?
I found a solution using 'send_file' instead. Providing the path to my file like so:
from flask import send_file
return send_file(pathToMyFile, as_attachment=True)
Related
I am trying to generate a list of tools with prices. The prices will be present in an excel file. How do I go about so that the excel file is read at first and I will just use pandas data frame to perform search and get the price. Note I don't want to read the excel file again. I tried adding
PRICE_FILE=pd.read_excel("./static/assets/tool_price.xlsx") in config.py so that it gets read when the app is initialized but I am having some error. This might be incorrect, I am not very sure.
I am using a flask web app with sqlite as my database (flask-sqlalchemy)
Here's how my main and config files look:
main.py
import os
from flask import Flask
from database import db
from config import LocalDevelopmentConfig
from flask_restful import Resource, Api
def create_app():
app = Flask(__name__, template_folder="templates")
app.config.from_object(LocalDevelopmentConfig)
db.init_app(app)
app.app_context().push()
return app
app = create_app()
from controllers import *
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
config.py
import os
import pandas as pd
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
DEBUG = False
SQLITE_DB_DIR = None
SQLALCHEMY_DATABASE_URI = None
SQLALCHEMY_TRACK_MODIFICATIONS = False
PRICE_FILE = None
class LocalDevelopmentConfig(Config):
SQLITE_DB_DIR = os.path.join(basedir)
SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(SQLITE_DB_DIR, "toolcodes.sqlite3")
PRICE_FILE=pd.read_excel("./static/assets/tool_price.xlsx")
DEBUG = True
I also have controllers.py which handles the GET and POST requests.
This is the structure of my project:
enter image description here
According to documentation for pandas, there is a "pandas.read_excel()" function which you can use to read excel files.
The file can be read using the file name as string or an open file object:
pd.read_excel('tmp.xlsx', index_col=0)
or
pd.read_excel(open('tmp.xlsx', 'rb'), sheet_name='Sheet3')
Note: Reading the excel file in the Config.py file is a bad idea. What you should do is, create a route that expect a post request, then save the file in a local directory.
Once the file is save you can pass the URL for the file to the pd.read_excel() function to perform some logic. example is:
from flask import Flask,url_for, render_template
import pandas as pd
import request
app = Flask(__name__)
#app.route("/read/excel",methods=['POST', 'GET'])
def read_excel_files():
if request.method == "POST":
# URL we are requesting excel file from
url = 'https://www.somelocation.com/prices.xlsx'
response = requests.get(url, allow_redirects=True)
#Save the file to some location (example: "./some/path/prices.xlsx")
file_location = "./some/path/prices.xlsx"
open('file_location , 'wb').write(response.content)
Then read the excel file with pandas
pandas_file = pd.read_excel(file_location,index_col=0)
Or if you are using flask url_for
excel_file = pd.read_excel(url_for('static',filename='documents/'+ excel_file_name),index_col=0)
return render_template("readExcel.html",title="Read Excel Files")
One you have successfully read the file with pandas, you can perform some logic on the file. You can also use Flask-WTForms to get the excel file from the user and pass it to the pd.read_excel() function
I am trying to provide the client side the option of downloading some files in Flask. There can be multiple files or a single file available for the user/client to download.
However I am not able to understand how to provide the user the option to download multiple files.
Here is what I have tried so far:
#app.route('/download_files')
def download():
count=0
download_list=[]
for path in pathlib.Path("dir1/dir2").iterdir():
if path.is_file():
for i in names:
if pathlib.PurePosixPath(path).stem == i:
count += 1
download_list.append(path)
return send_file(download_list, as_attachment=True, mimetype="text/plain", download_name="Downloaded Files", attachment_filename="Generated Files")
This does not work properly even with a single file. The file type I am trying to download is text file with the extension .sql .
Will I somehow have to zip multiple files and then provide the download option? Please guide with my available options.
In order to offer several files together as a download, you only have the option of compressing them in an archive.
In my example, all files that match the specified pattern are listed and compressed in a zip archive. This is written to the memory and sent by the server.
from flask import Flask
from flask import send_file
from glob import glob
from io import BytesIO
from zipfile import ZipFile
import os
app = Flask(__name__)
#app.route('/download')
def download():
target = 'dir1/dir2'
stream = BytesIO()
with ZipFile(stream, 'w') as zf:
for file in glob(os.path.join(target, '*.sql')):
zf.write(file, os.path.basename(file))
stream.seek(0)
return send_file(
stream,
as_attachment=True,
download_name='archive.zip'
)
You haven't provided a code sample where you actually getting these files or this file. Minimum working example would be like this:
from flask import Flask, request
app = Flask(__name__)
#app.route('/download_files', methods=['POST'])
def download():
file = request.files['file'] # for one file
files = request.files.getlist("file[]") # if there're multiple files provided
if __name__ == "__main__":
app.run()
After what your file variable will be an object of werkzeug.FileStorage and files variable will be a list of these objects.
And to download all these files you can check this question.
I am using a Flask application to update some PDF files, convert them to an Excel file and send this file back to the user. I am using an instance folder to store the pdf and the excel files.
But when the user press the button "Download" in order to download the generated Excel file, an old file is downloaded (from an older session).
Moreover, when I try to change my code, for example, I changed the name of this Excel file: I can see the new name in the instance folder, but when I download the file with the webapp, it is still the old name (and old file). I have no idea where the webapp is looking for this old file...
MEDIA_FOLDER = '/media/htmlfi/'
app = Flask(__name__)
app.config.from_object(Config)
INSTANCE_FOLDER = app.instance_path
app.config['UPLOAD_FOLDER'] = INSTANCE_FOLDER+MEDIA_FOLDER
#app.route('/file/')
def send():
folder = app.config['UPLOAD_FOLDER']
try:
return send_file(folder+ "file.xlsx", as_attachment=True)
finally:
os.remove(folder+ "file.xlsx")
<a href="{{ url_for('send') }}" ><button class='btn btn-default'>DOWNLOAD</button></a>
I am really new to webapp in general, thank you for your help :)
send_file takes a cache_timeout parameter which is the number of seconds you want to cache the download. By default is 12 hours.
return send_file(
file.file_path(),
as_attachment=True,
cache_timeout=app.config['FILE_DOWNLOAD_CACHE_TIMEOUT'],
attachment_filename=file.file_name
)
http://flask.pocoo.org/docs/1.0/api/
How to implement an API endpoint to download excel file using Flask-RestPlus?
Previously I had implemented similar function using Pyramid. However that method didn't work here.
Here is the old code snippet:
workBook = openpyxl.Workbook()
fileName = 'Report.xls'
response = Response(content_type='application/vnd.ms-excel',
content_disposition='attachment; filename=%s' % fileName)
workBook.save(response)
return response
Thanks for the help.
send_from_directory provides a secure way to quickly expose static files from an upload folder or something similar when using Flask-RestPlus
from flask import send_from_directory
import os
#api.route('/download')
class Download(Resource):
def get(self):
fileName = 'Report.xls'
return send_from_directory(os.getcwd(), fileName, as_attachment=True)
I have assumed file is in current working directory. The path to download file can be adjusted accordingly.
I uploaded a CSV file test.csv to Google Cloud Storage's bucket. The resulting public_url is like this
https://storage.googleapis.com/mybucket/test-2017-04-11-025727.csv
Originally `test.csv' has some row and column containing numbers like this
6,148,72,35,0,33.6,0.627,50,1
8,183,64,0,0,23.3,0.672,32,1
...
...
I uploaded the file by referring to bookshelf tutorial --> https://github.com/GoogleCloudPlatform/getting-started-python no 6-pubsub. The uploaded file will be saved with timestamp added to it.
Now I want to download the file that I uploaded to the bucket by using requests
Here is what I've been working on. The original sample is at 6-pubsub/bookshelf/crud.py. Below is script that I already edited based on the original sample.
from machinelearning import get_model, oauth2, storage, tasks
from flask import Blueprint, current_app, redirect, render_template, request, session, url_for
import requests
import os
...
...
crud = Blueprint('crud', __name__)
save_folder = 'temp/'
def upload_csv_file(file):
...
...
return public_url
...
...
#crud.route('/add', methods=['GET', 'POST'])
def add():
data = request.form.to_dict(flat=True)
# This will upload the file that I pushed from local directory to GCS
if request.method == 'POST':
csv_url = upload_csv_file(request.files.get('file'))
if csv_url:
data['csvUrl'] = csv_url
# I think this is not working. This should download back the file and save it to a temporary folder inside current working directory
response = requests.get(public_url)
if not os.path.exists(save_folder):
os.makedirs(save_folder)
with open(save_folder + 'testdata.csv', 'wb') as f:
f.write(response.content)
...
...
I opened folder temp and check the testdata.csv. It shows me an error like this inside the CSV file.
<?xml version='1.0' encoding='UTF-8'?><Error><Code>AccessDenied</Code><Message>Access denied.</Message><Details>Anonymous users does not have storage.objects.get access to object mybucket/test-2017-04-11-025727.csv.</Details></Error>
I was hoping testdata.csv will have same contents like test.csv but it did not.
I already recheck my OAuth client and secret, bucket id on config.py but the error still there.
How do I solve this kind of error?
Thank you in advanced.
I solved it. It is just like mr #Brandon Yarbrough said that the bucket's object is not publicly readable.
To make the bucket public, taking from this link --> https://github.com/GoogleCloudPlatform/gsutil/issues/419
gsutil defacl set public-read gs://<bucket_name>