mikelowry
mikelowry

Reputation: 1717

create excel file from DataFrame and allow download in flask, error: file format/extension not valid

I've created a simple Flask app that turns a Pandas Dataframe into an excel file. The file gets downloaded when I go to the link, however, I'm just getting the following error once I try and open the file:

Excel cannot open the file 'df.xlsx' because the file format or file extension is not valid. Verify that the files has not been corrupted and that the file extension matches the format of the file.

Am I missing something here?

 @app.route('/download', methods=["GET"])
 def download_excel():
    df = pd.DataFrame({'Name': ['Tesla','Tesla','Toyota','Ford','Ford','Ford'],
                   'Type': ['Model X','Model Y','Corolla','Bronco','Fiesta','Mustang']})

    #create an output stream
    output = BytesIO()
    writer = pd.ExcelWriter(df, engine='xlsxwriter')
    df.to_excel(writer, sheet_name='Sheet1')

    #the writer has done its job
    writer.close

    #go back to the beginning of the stream
    output.seek(0)
    
    #finally return the file
    return send_file(output, attachment_filename="df.xlsx", as_attachment=True)

Upvotes: 0

Views: 1630

Answers (1)

bas
bas

Reputation: 15722

The problem is that you're passing the dataframe to ExcelWriter's path parameter instead of the BytesIO object (output).

writer = pd.ExcelWriter(df, engine='xlsxwriter')

The ExcelWriter documentation says the following on the path parameter:

path: str or typing.BinaryIO Path to xls or xlsx or ods file.


So you could do something like this instead:

from flask import Flask, send_file
import pandas as pd
from io import BytesIO

app = Flask(__name__)


@app.route("/download", methods=["GET"])
def download_excel():
    df = pd.DataFrame(
        {
            "Name": ["Tesla", "Tesla", "Toyota", "Ford", "Ford", "Ford"],
            "Type": ["Model X", "Model Y", "Corolla", "Bronco", "Fiesta", "Mustang"],
        }
    )

    output = BytesIO()

    with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
        df.to_excel(writer, sheet_name="Sheet1")

    output.seek(0)

    return send_file(output, attachment_filename="df.xlsx", as_attachment=True)

Upvotes: 2

Related Questions