【问题标题】:Getting an empty file when served by django由 django 提供服务时获取空文件
【发布时间】:2012-01-05 10:41:58
【问题描述】:

我有以下代码用于通过 django 管理文件下载。

def serve_file(request, id):

    file = models.X.objects.get(id=id).file #FileField
    file.open('rb')
    wrapper = FileWrapper(file)
    mt = mimetypes.guess_type(file.name)[0]
    response = HttpResponse(wrapper, content_type=mt)

    import unicodedata, os.path
    filename = unicodedata.normalize('NFKD', os.path.basename(file.name)).encode("utf8",'ignore')
    filename = filename.replace(' ', '-') #Avoid browser to ignore any char after the space

    response['Content-Length'] = file.size
    response['Content-Disposition'] = 'attachment; filename={0}'.format(filename)

    #print response
    return response

不幸的是,我的浏览器在下载时得到一个空文件。

打印出来的响应似乎是正确的:

Content-Length: 3906
Content-Type: text/plain
Content-Disposition: attachment; filename=toto.txt

blah blah ....

我有类似的代码运行正常。我看不出有什么问题。有什么想法吗?

PS:我已经测试了here 提出的解决方案并得到了相同的行为

更新: 将wrapper = FileWrapper(file) 替换为wrapper = file.read() 似乎可以解决问题

更新:如果我评论 print response,我会遇到类似的问题:。该文件是空的。唯一的区别:FF 检测到 20 字节大小。 (文件比这个大)

【问题讨论】:

    标签: python django download


    【解决方案1】:

    文件对象是一个可交互的对象,也是一个生成器。在用尽之前只能阅读一次。然后你必须创建一个新的,使用一种方法从对象的开头重新开始(例如:seek())。

    read()返回一个字符串,可以多次读取没有问题,这就是它解决你的问题的原因。

    所以只要确保如果你使用像对象这样的文件,你不会连续两次读取它。例如:不打印,然后返回。

    【讨论】:

    • 好点!但是我已经评论了打印并且仍然有类似的行为(事实上,我添加了打印以尝试理解 pb)。查看我的更新
    • 是的,但是有什么可以证明响应只迭代了一次?响应毕竟使用您的文件包装器来设置其内容。
    【解决方案2】:

    来自django documentation

    FieldFile.open(mode='rb') 行为类似于标准 Python open() 方法并在模式下打开与此实例关联的文件 由模式指定。

    如果它像 pythons open 一样工作,那么它应该返回一个文件对象,并且应该像这样使用:

    f = file.open('rb')
    wrapper = FileWrapper(f)
    

    【讨论】:

    • 看来file.open除了修改文件实例没有返回任何东西
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 2012-03-13
    相关资源
    最近更新 更多