简体   繁体   中英

How do I download xlsx file with Django?

I tried to make a button for downloading a .xlsx file using Django so I followed this tutorial: https://xlsxwriter.readthedocs.io/example_django_simple.html

Now I have an HTTP response, but no download prompt is showing.

Here are some parts of my code :

views.py:

def xlsx(request):
    if request.method == "POST":
        output = io.BytesIO()
        workbook = xlsxwriter.Workbook(output)
        worksheet = workbook.add_worksheet("hello")
        worksheet.write(0,0, 'Client')
        workbook.close()
        output.seek(0)

    filename = 'EdedocBilling.xlsx'
    response =  HttpResponse(output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
    return response

index.html

<form>...</form>
<button type = "button" id = "saveID"
    onclick = "$.ajax({
        type: 'POST',
        url: 'xlsx',
        async: false,
        data: $('form').serialize(),
        success : console.log(' Success')
    })">
    Generate
</button>

I removed the code where I process the data because the generated .xlsx works fine. (I tested creating the file on the server and it worked.)

Here are the HTTP response headers:

HTTP/1.1 200 OK
Date: Thu, 08 Jul 2021 14:47:37 GMT
Server: WSGIServer/0.2 CPython/3.8.8
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="EdedocBilling.xlsx"
X-Frame-Options: DENY
Content-Length: 5252
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin

Does somebody have a solution? Thanks!

This is due to the nature of AJAX, and how browsers handle all of this.

Have a look at the different answers to question Is it possible to download a file with HTTP POST? .

Using MEDIA and a URL Pattern

Return a URL in the response of the POST request and implement a URL pattern that delivers the file content.

This is of course a bit more effort but it would be a good solution if you website has to scale.

Steps:

  1. create a Django model for the Excel sheet and store the generated files in the MEDIA folder: see https://docs.djangoproject.com/en/3.2/topics/files/ on details how to do this. The model should at least have a slug and a file field, and maybe a date field for handling expiry if you want the access to be only temporary available.
  2. in your urls.py create a route that identifies a specific excel, eg /generated/slug:slug.xls. Implement get_absolute_url() on your model returning this route.
  3. from your post request do not return the generated file but return the result of obj.get_absolute_url as text content to be handled in JS.
  4. in your AJAX success handler, redirect the browser to this URL.
  5. in the view of this route, return the file. You can also check for authorization and expiry here.

In a production setup, you can also configure your Reverse Proxy (eg nginx) to deliver the files, and your Django view only sets a header (X-Accel-Redirect) that indicates to the proxy which file to deliver. See https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/ for more on this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM