【问题标题】:Download a file in django with a button using xmlhttprequest使用 xmlhttprequest 在 django 中通过按钮下载文件
【发布时间】:2017-07-04 12:11:34
【问题描述】:

我查看了许多相同的问题,但没有一个能解决我的问题, 我正在尝试使用按钮下载在我的视图中生成的文件。 问题:点击下载按钮时我得到一个空文件

我的看法:

class dumpView(View):

template_name = 'download.html'
def get(self, request):
    file = open("/home/test.pdf", "rwbt")
    response = HttpResponse(file.read(), content_type="application/pdf")
    response['Content-Disposition'] = 'attachement; filename=%s' % file
    return render(request, 'download.html')

我的网址:

url(r'^dump/', dumpView.as_view()),

我的模板:

 {% extends 'base.html' %} 
 {% load staticfiles %} 
 {% block content %}
 <div class="container">
 <div class="row">
    <div class="jumbotron">
        <div class="row">
            <center>
                <a href="javascript:void(0)" class="btn btn-primary btn-lg dump">Download</a>
            </center>
        </div>
    </div>
</div>
</div>
{% endblock %} 
{% block javascript %}
<script src="{% static 'js/home.js' %}"></script>
{% endblock %}

我的 Django 视图正在呈现响应。我确实在 UI 中的带有类转储的按钮上添加了一个点击处理程序,以向“/dump”URL 发出 XHR 请求,并以 blob 形式接收响应并下载具有自定义名称和日期的文件。

我的 js:

$(".dump").on("click", function() {
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    var a, today;
    if (xhttp.readyState === 4 && xhttp.status === 200) {
        a = document.createElement('a');
        a.href = window.URL.createObjectURL(xhttp.response);
        today = new Date();
        a.download = "file_" + today.toDateString().split(" ").join("_") + ".pdf";
        a.style.display = 'none';
        document.body.appendChild(a);
        return a.click();
    }
};
xhttp.open("GET", "/dump", true);
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.responseType = 'blob';
xhttp.send();
});

【问题讨论】:

  • 您如何在视图中使用“响应”变量?
  • 我不返回响应以便我可以使用我的模板。如果我只是做出“返回响应”,我可以直接下载文件,而无需我的模板和我的按钮。

标签: javascript python django download


【解决方案1】:

在您看来,我建议在您的回复中添加尺寸

content = file(filename).read()
response = HttpResponse(content, content_type='text/plain')
response['Content-Length'] = os.path.getsize(filename)
response['Content-Disposition'] = 'attachment; filename=%s' % 'my_pdf.pdf'

正如@bob-vork 刚才所说,来自Content-Disposition 的文件名不应该是python file 对象,而是您下载的名称。

如何在 urls.py 中注册视图,然后将 javascript 替换为:

<input type="button" value="Download" onclick="window.open('download_my_pdf')">

编辑:

既然您要使用建议的 HTML,那么我将在我的解决方案中提供更多详细信息。

首先,您可以删除home.js。如你所见

<a href="javascript:void(0)" class="btn btn-primary btn-lg dump">Download</a>

变成

<input type="button" value="Download" onclick="window.open('download_my_pdf')">

你的views.py应该直接返回response

from django.http import HttpResponse
from wsgiref.util import FileWrapper

@login_required
def download_pdf(request):
    filename = 'whatever_in_absolute_path__or_not.pdf'
    content = FileWrapper(filename)
    response = HttpResponse(content, content_type='application/pdf')
    response['Content-Length'] = os.path.getsize(filename)
    response['Content-Disposition'] = 'attachment; filename=%s' % 'whatever_name_will_appear_in_download.pdf'
    return response

也要注意放置正确的content_type。请注意,我没有测试视图(尤其是 FileWrapper),我修改了一些纯文本代码。如果将 pdf 视为文本文件,这也是为什么会出现 TypeError 的原因。

在 urls.py 中

urlpatterns = (
    [...]
    url('download_my_pdf', download_pdf),
)

【讨论】:

  • 感谢您的回答,我确实将 javascript 替换为您建议的内容,并将 url 替换为:“url(r'^dump/', dumpView.as_view(), name='download_my_pdf')” ,按下按钮时无法下载文件。
  • 当我正确使用 content 和 getsize() 时,我得到一个 TypeError “强制转换为 Unicode:需要字符串或缓冲区,找到文件”
【解决方案2】:

在您看来,您将Content-Disposition 设置为attachment; filename=...,但您附加了文件对象。我的猜测是浏览器可能需要一个文件名,最好使用正确的扩展名。

我在 Django 项目中也有类似的观点,我也引用了文件名,但我不确定是否有必要

编辑:另外,“附件”中有错字,删除多余的“e”,看看是否有帮助

【讨论】:

  • 感谢您的回答,但这并不能解决问题,我试过这个:“response['Content-Disposition'] = 'attachment; filename=%s' % test.pdf”和还有 "response['Content-Disposition'] = 'attachment; filename=%s' % /home/test.pdf" 但我有一个空文件。
  • P.s:我认为我的 js 没有收到来自视图的响应,因为当我尝试返回响应时,我可以在没有模板或按钮的情况下成功下载文件
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-16
  • 2018-05-05
  • 2019-03-22
  • 2018-06-22
  • 1970-01-01
  • 2018-06-28
相关资源
最近更新 更多