P.S. Rao
P.S. Rao

Reputation: 47

download excel by using Ajax andFlask

I'm trying to download the excel from flask using Ajax call. it's showing the response code as 200 but excel is not downloading and the error messages are as follows.

Ajax Request :

$("#genExcel").on("click", function() { var xhttp = new XMLHttpRequest();

                // Data to post
                var dataarray = {};

                // Use XMLHttpRequest instead of Jquery $ajax

                xhttp.onreadystatechange = function() {
                    var a;
                    if (xhttp.readyState === 4 && xhttp.status === 200) {
                        // Trick for making downloadable link
                        a = document.createElement('a');
                        const objectURL = window.URL.createObjectURL(xhttp.response);
                        a.href = objectURL

                        //const objectURL = URL.createObjectURL(object)

                        // Give filename you wish to download
                        a.download = "test-file.xlsx";
                        a.style.display = 'none';
                        document.body.appendChild(a);
                        a.click();
                    }
                };
                // Post data to URL which handles post request
                xhttp.open("POST", '/genexcel');
                xhttp.setRequestHeader("Content-Type", "application/json");
                // You should set responseType as blob for binary responses
                //xhttp.responseType = 'blob';
                xhttp.send(JSON.stringify(dataarray));
            });

Flask function :

@app.route('/genexcel', methods=["GET", "POST"])
def createExcel():
    if request.method == 'POST':
        data = request.json  
        # process json data        
        return send_file(strIO, attachment_filename='test.xlsx',  as_attachment=True)

Errors :

1 [Report Only] Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src * blob:".

2 Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.

at XMLHttpRequest.xhttp.onreadystatechange

error and response

Upvotes: 0

Views: 2116

Answers (2)

Lazypaddy
Lazypaddy

Reputation: 128

Hopefully I've understood you correctly. Here is a very simple example using the data Array you provided. You could modify to suit your needs:

Flask Functions

from flask import Flask, render_template, request, url_for, send_file
import xlsxwriter

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/genexcel', methods=["GET", "POST"])
def createExcel():
    if request.method == 'POST':
        data = request.get_json(force=True)
        # process json data
        createExcel(data['data'])

    file_path = 'static/files/test.xlsx'
    return send_file(file_path, attachment_filename='test.xlsx', as_attachment=True)

def createExcel(data):
    workbook = xlsxwriter.Workbook('static/files/test.xlsx')
    worksheet = workbook.add_worksheet()

    row_no = 0
    col_no = 0
    for row in data:
        col_no = 0
        for entry in row:
            worksheet.write(row_no, col_no, entry)
            col_no += 1
        row_no += 1

    workbook.close()

app.run(debug=True, port=5010)

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Test</title>
  </head>
  <body>
    Testing
    <button id="genExcel">Direct Download</button>
    <button id="genExcelFlask">Flask Download</button>
  </body>

  <script>
    var btn = document.getElementById("genExcel");
    var btnFlask = document.getElementById("genExcelFlask");
    var dataArray = {
      data: [
        [1, "A", 100],
        [2, "B", 200],
      ],
    };

    btn.addEventListener("click", (e) => {
      fetch("https://jsonplaceholder.typicode.com/todos/1")
        .then((resp) => resp.blob())
        .then((blob) => {
          const url = window.URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.style.display = "none";
          a.href = url;
          // the filename you want
          a.download = "todo-1.json";
          document.body.appendChild(a);
          a.click();
          window.URL.revokeObjectURL(url);
          alert("your file has downloaded!"); // or you know, something with better UX...
        })
        .catch(() => alert("oh no!"));
    });

    btnFlask.addEventListener("click", (e) => {
      console.log(JSON.stringify(dataArray));

      fetch("{{ url_for('createExcel') }}", {
        method: "post",
        body: JSON.stringify(dataArray),
      })
        .then((resp) => resp.blob())
        .then((blob) => {
          const url = window.URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.style.display = "none";
          a.href = url;
          // the filename you want
          a.download = "test.xlsx";
          document.body.appendChild(a);
          a.click();
          window.URL.revokeObjectURL(url);
          alert("your file has downloaded!"); // or you know, something with better UX...
        })
        .catch(() => alert("oh no!"));
    });
  </script>
</html>

Upvotes: 1

Lazypaddy
Lazypaddy

Reputation: 128

Here is an example using the fetch API. The first button just does a straight JS download. The second button uses the Flask route to do the download. Hope it helps.

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Test</title>
  </head>
  <body>
    Testing
    <button id="genExcel">Direct Download</button>
    <button id="genExcelFlask">Flask Download</button>
  </body>

  <script>
    var btn = document.getElementById("genExcel");
    var btnFlask = document.getElementById("genExcelFlask");

    btn.addEventListener("click", (e) => {
      fetch("https://jsonplaceholder.typicode.com/todos/1")
        .then((resp) => resp.blob())
        .then((blob) => {
          const url = window.URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.style.display = "none";
          a.href = url;
          // the filename you want
          a.download = "todo-1.json";
          document.body.appendChild(a);
          a.click();
          window.URL.revokeObjectURL(url);
          alert("your file has downloaded!"); // or you know, something with better UX...
        })
        .catch(() => alert("oh no!"));
    });

    btnFlask.addEventListener("click", (e) => {
      fetch("{{ url_for('createExcel') }}")
        .then((resp) => resp.blob())
        .then((blob) => {
          const url = window.URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.style.display = "none";
          a.href = url;
          // the filename you want
          a.download = "test.xlsx";
          document.body.appendChild(a);
          a.click();
          window.URL.revokeObjectURL(url);
          alert("your file has downloaded!"); // or you know, something with better UX...
        })
        .catch(() => alert("oh no!"));
    });
  </script>
</html>

Flask Function

from flask import Flask, render_template, request, url_for, send_file

@app.route('/genexcel', methods=["GET", "POST"])
def createExcel():
    if request.method == 'POST':
        data = request.json
        print(data)
        # process json data

    file_path = 'static/files/test.xlsx'
    return send_file(file_path, attachment_filename='test.xlsx', as_attachment=True)

Upvotes: 0

Related Questions