2010-03-17 93 views
7

我正在嘗試使用HttpResponse下載CSV文件,以確保瀏覽器將其視爲附件。我按照提供的說明here但我的瀏覽器不會提示「另存爲」對話框。我無法弄清楚我的功能有什麼問題。所有的幫助表示讚賞。下載django中的csv文件

 
    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) 

快樂的帕特節!

回答

1

謝謝大家對你的建議。我選了一些新的技巧:) 但是我想我已經在這裏找到了我的問題的答案: Downloading CSV via AJAX 我的「savefile」函數是通過Ajax請求調用的,看起來ajax有一個限制,其中「另存爲對話框「不會出現,不管HTTP標頭是什麼。

我應該提到我使用Ajax來調用這個函數,但是從來沒有想到這可能是一個問題:) Thankyou StackOverflow!

5

您是否嘗試指定內容類型? 例如

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 
+0

試過了,依然不起作用。我可以在FireBug中看到響應和標題,但我沒有看到對話框。 – spyder 2010-03-17 19:39:36

+0

試試我目前的編輯。 – Cerin 2010-03-18 17:30:01

+0

我試過但沒有工作。請看我的回覆,我發現這個問題與django無關。謝謝 – spyder 2010-03-18 17:45:36

7

如果該文件是靜態(即不爲此請求專門產生的),你不應該通過Django的服務反正它。你應該配置一些路徑(比如/ static /)供你的web服務器使用,並保存所有的django開銷。

如果該文件是動態,有2個選項:

  1. 在內存中創建它,並從Django的服務於它。
  2. 在磁盤上創建它,並返回一個HttpResponseRedirect給它,以便您的Web服務器自行處理下載(如果文件非常大,則應使用此選項)。

至於動態服務它,我一直在使用下面的代碼(這是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(...)傳球在列表列表中,列表(具有相同的鍵),查詢集,值查詢集

+0

它是爲「this」請求而生成的,並暫時存儲在/ static /下。 – spyder 2010-03-17 21:51:30

+0

在您的評論後編輯。 – 2010-03-18 06:49:39

+0

感謝您的詳細信息! – spyder 2010-03-18 17:44:19

0

如果不用雙引號括起文件名,它有什麼區別嗎?示例代碼不引用的文件名:

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

,但你的代碼做:

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

謝謝,試過了......沒有快樂。 – spyder 2010-03-17 23:42:20

0

托馬斯,我曾經使用過一個Ajax函數來保存和下載這個文件。看來在這種情況下,無論標題如何,「另存爲」框都不會出現。我只是使用JavaScript來下載該文件。 window.open(「path/to/file」); 它的竅門。我在IE6和Firefox上測試過,出現對話框。