在django中下载csv文件

时间:2010-03-17 18:33:48

标签: django download

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

  dev savefile(request):
        try:
            myfile = request.GET['filename']
            filepath = settings.MEDIA_ROOT + 'results/'
            destpath = os.path.join(filepath, myfile)
            response = HttpResponse(FileWrapper(file(destpath)), mimetype='text/csv' ) 
            response['Content-Disposition'] = 'attachment; filename="%s"' %(myfile)
            return response
        except Exception, err:
            errmsg = "%s"%(err)
            return HttpResponse(errmsg)

快乐的帕特日!

5 个答案:

答案 0 :(得分:9)

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

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

  1. 在内存中创建并从django提供。
  2. 在磁盘上创建它,并向其返回一个HttpResponseRedirect,以便您的网络服务器处理下载本身(如果文件非常大,您应该使用此选项)。
  3. 至于动态提供它,我一直在使用以下代码(这是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)
    

    要使用它,只需使用返回CSVResponse(...)传递列表列表,dicts列表(使用相同的键),QuerySet,ValuesQuerySet

答案 1 :(得分:5)

您是否尝试过指定内容类型? e.g。

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:0)

如果不将文件名用双引号括起来会有什么不同吗?示例代码不引用文件名:

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

但您的代码确实:

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