在 django 中下载 csv 文件

Posted

技术标签:

【中文标题】在 django 中下载 csv 文件【英文标题】:Downloading a csv file in django 【发布时间】:2011-01-28 17:22:17 【问题描述】:

我正在尝试使用 HttpResponse 下载 CSV 文件,以确保浏览器将其视为附件。我按照here 提供的说明进行操作,但我的浏览器没有提示“另存为”对话框。我无法弄清楚我的功能有什么问题。感谢所有帮助。

开发保存文件(请求): 尝试: myfile = request.GET['文件名'] 文件路径 = settings.MEDIA_ROOT + '结果/' destpath = os.path.join(文件路径,我的文件) response = HttpResponse(FileWrapper(file(destpath)), mimetype='text/csv') response['Content-Disposition'] = '附件;文件名="%s"' %(我的文件) 返回响应 除了异常,错误: errmsg = "%s"%(错误) 返回 HttpResponse(errmsg)

帕特节快乐!

【问题讨论】:

【参考方案1】:

如果文件是静态(即不是专门为此请求生成的),则无论如何都不应该通过 django 提供它。您应该配置一些路径(如 /static/)以供您的网络服务器提供服务,并节省所有 django 开销。

如果文件是动态的,有2个选项:

    在内存中创建它并从 django 提供它。 在磁盘上创建它,并向它返回一个 HttpResponseRedirect,以便您的网络服务器自己处理下载(如果文件很大,您应该使用此选项)。

至于动态服务,我一直在使用下面的代码(这是ExcelResponse的简化版)

import StringIO
from django.db.models.query import ValuesQuerySet, QuerySet

class CSVResponse(HttpResponse):

  def __init__(self, data, output_name='data', headers=None, encoding='utf8'):

    # Make sure we've got the right type of data to work with
    valid_data = False
    if isinstance(data, ValuesQuerySet):
        data = list(data)
    elif isinstance(data, QuerySet):
        data = list(data.values())
    if hasattr(data, '__getitem__'):
        if isinstance(data[0], dict):
            if headers is None:
                headers = data[0].keys()
            data = [[row[col] for col in headers] for row in data]
            data.insert(0, headers)
        if hasattr(data[0], '__getitem__'):
            valid_data = True
    assert valid_data is True, "CSVResponse requires a sequence of sequences"

    output = StringIO.StringIO()
    for row in data:
        out_row = []
        for value in row:
            if not isinstance(value, basestring):
                value = unicode(value)
            value = value.encode(encoding)
            out_row.append(value.replace('"', '""'))
        output.write('"%s"\n' %
                     '","'.join(out_row))            
    mimetype = 'text/csv'
    file_ext = 'csv'
    output.seek(0)
    super(CSVResponse, self).__init__(content=output.getvalue(),
                                        mimetype=mimetype)
    self['Content-Disposition'] = 'attachment;filename="%s.%s"' % \
        (output_name.replace('"', '\"'), file_ext)

要使用它,只需使用 return CSVResponse(...) 传入列表列表、dict 列表(具有相同键)、QuerySet、ValuesQuerySet

【讨论】:

它是为“this”请求动态生成的,并临时存储在/static/下。【参考方案2】:

Thomas,我使用了一个 Ajax 函数来保存和下载这个文件。在这种情况下,无论标题如何,似乎都不会出现“另存为”框。我只是使用 javascript 来下载该文件。 window.open("路径/到/文件"); 它成功了。我在IE6和Firefox上测试,出现对话框。

【讨论】:

【参考方案3】:

感谢大家的建议。我选择了一些新技巧:) 但是我想我在这里找到了我的问题的答案: Downloading CSV via AJAX 我的“保存文件”函数是通过 Ajax 请求调用的,似乎 ajax 有一个限制,即无论 HTTP 标头是什么都不会出现“另存为对话框”。

我应该提到我使用 Ajax 来调用这个函数,但我从来没有想过这可能是一个问题。:) 谢谢 ***!

【讨论】:

【参考方案4】:

您是否尝试指定内容类型? 例如

response['Content-Type'] = 'application/x-download';

编辑:

请注意,此代码为我成功触发了“另存为”对话框。注意我直接在 mimetype 参数中指定“application/x-download”。您可能还想重新检查您的代码,并确保您的文件路径正确,并且 FileWrapper() 没有做一些奇怪的事情。

def save_file(request):
    data = open(os.path.join(settings.PROJECT_PATH,'data/table.csv'),'r').read()
    resp = django.http.HttpResponse(data, mimetype='application/x-download')
    resp['Content-Disposition'] = 'attachment;filename=table.csv'
    return resp

【讨论】:

试过了,还是不行。我可以在 FireBug 中看到响应和标头,但没有看到对话框。 我试过但没有用。请看我的回复,我发现这个问题与 django 无关。谢谢 如果你使用我的方法和普通链接,它和ajax的效果一样,它不会离开当前页面。【参考方案5】:

如果您不将文件名括在双引号中,会有什么不同吗?示例代码没有引用文件名:

response['Content-Disposition'] = 'attachment; filename=foo.xls'

但您的代码可以:

response['Content-Disposition'] = 'attachment; filename="foo.xls"'

【讨论】:

我必须用引号将文件名括起来才能正常工作。

以上是关于在 django 中下载 csv 文件的主要内容,如果未能解决你的问题,请参考以下文章

htmljs简单实现含中文csv文件下载(后端为django)

从 django 应用程序下载一个文本/csv 文件,该文件从数据库查询中填充 HTML 表

python pandas dataframe csv django下载

django生成CSV文件

以 csv 格式下载包含来自多个模型的数据的 zip 文件

如何使用 csv.DictReader 在 django 中上传和读取 csv 文件?