Here is the way I download my zip of excel files, with the zip file being created on-the-fly. In this example, the individual excel files reside in my AWS instance.
NOTE: This entire process must be achieved within 30 seconds if hosting on Heroku due to the web process time limit; unless you implement this asynchronously.
The href
assoc. with the button to invoke the download looks similar to the following:
http://127.0.0.1:8050/download_zip/?filename=2020_06May_13May_Excel.zip&file_0=2020/May/06May_13May/20-05-06_Data.xlsx&file_1=2020/May/06May_13May/20-05-06_Data2.xlsx&file_2=2020/May/06May_13May/20-05-06_Data3.xlsx&num_files=3
Here is the code that handles the downloading of these files from my AWS instance, creating a zip to contain them, and then downloading to the user.
import flask
import io
import zipfile
@app.server.route('/download_zip/')
def download_zip_file():
# Name of the zip file
filename = flask.request.args.get('filename')
# Num of files to process
num_files = flask.request.args.get('num_files')
# All files passed in via url string are of the format file_<filename>
files = []
for file in range(int(num_files)):
files.append(flask.request.args.get('file_' + str(file)))
# Loop thru files and add to zip
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED, False) as zip_file:
for file in files:
# aws.download is an internal function to download the file from my AWS S3 instance
file_obj = aws.download(file)
zip_file.writestr(file.split('/')[-1], file_obj['Body'].read())
return flask.Response(
zip_buffer.getvalue(),
mimetype='binary/octet-stream',
headers={"Content-Disposition": "attachment;filename={}".format(filename)}
)
Here is the aws.download()
function:
import boto3
# Download a file from the bucket
def download(key):
# Create connection to the bucket
s3_resource = boto3.resource('s3')
bucket = s3_resource.Bucket(S3_BUCKET)
# Return file object
return bucket.Object(key).get()
Hope this helps and you can adapt to your needs.