Force Download existing JSON file instead of displaying it with Django

Viewed 748

My webpage has a functionality that lets users request fairly large json files (3MB+) to be generated. The generation process takes some time and I send them an email with a download link once it is ready.

My problem is that clicking the download URL will open the content of the json file in the browser instead of starting a download dialog.

I have found this question: Serving .json file to download but the solution reserialize the json file into the response:

mixed_query = list(invoices) + list(pcustomers)
json_str = serializers.serialize('json', mixed_query))
response = HttpResponse(json_str, content_type='application/json')
response['Content-Disposition'] = 'attachment; filename=export.json'

As the JSON file already exists, I do not want to rewrite it entirely within the response. I just want users to download the already generated file.

How can I force the URL to start a download when reached?

I am using Django 3.1, with Python 3.6

Here is the email template sent to users once the download link is ready:

{% extends "emails/email_css.html" %}

{% block mail_content %}
    <p>Hi, {{ username }}</p>

    <p>Your export for {{ export_name }} is ready!</p>
    <p>The file will be available for download for 2 days, or until you request a new export.</p>

    <a class="download_button" type="button" href={{ download_url }}>Download</a>
{% endblock %}

Edit: I also tried this solution How to download file using anchor tag <a> but the json file still gets shown in the browser instead of being downloaded.

2 Answers

I eventually found how to do it, by returning a FileResponse with as_attachment=True.

from django.http import FileResponse

def download_export(request):
    response = FileResponse(open("path/to/file.json", 'rb'), as_attachment=True,
                            filename="file_name.json")
    return response

Try adding the download property to the <a> tag. You can optionally specify a download filename or not.

Without filename:

<a class="download_button" type="button" href={{ download_url }} download>Download</a>

With filename:

<a class="download_button" type="button" href={{ download_url }} download="someJsonFile.json">Download</a>

See docs here for the download property. Also the related StackOverflow post here.

Related