1. 程式人生 > >Django中生成和下載csv檔案

Django中生成和下載csv檔案

有時候我們做的網站,需要將一些資料,生成有一個CSV檔案給瀏覽器,並且是作為附件的形式下載下來。

生成小的CSV檔案:

def index(request):
    response = HttpResponse(content_type='text/csv')
    # attachment 代表這個csv檔案作為一個附件的形式下載
    # filename='abc.csv' 指定下載的檔名字
    response['Content-Disposition'] = "attachment;filename='abc.csv'"
    writer = csv.
writer(response) writer.writerow(['username','age','height', 'weight']) writer.writerow(['zhiliao','18','180','100']) # 在這裡並不會指定檔名字。 return response

程式碼講解:

  1. 我們在初始化HttpResponse的時候,指定了Content-Type為text/csv,這將告訴瀏覽器,這是一個csv格式的檔案而不是一個HTML格式的檔案,如果用預設值,預設值就是html,那麼瀏覽器將把csv格式的檔案按照html格式輸出,這肯定不是我們想要的。
  2. 第二個我們還在response中新增一個Content-Disposition頭,這個東西是用來告訴瀏覽器該如何處理這個檔案,我們給這個頭的值設定為attachment;,那麼瀏覽器將不會對這個檔案進行顯示,而是作為附件的形式下載,第二個filename="abc.csv"是用來指定這個csv檔案的名字。
  3. 我們使用csv模組的writer方法,將相應的資料寫入到response中。

將csv檔案定義成模板:

我們還可以將csv格式的檔案定義成模板,然後使用Django內建的模板系統,並給這個模板傳入一個Context物件,這樣模板系統就會根據傳入的Context物件,生成具體的csv檔案。示例程式碼如下:

def template_csv_view(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = "attachment;filename='abc.csv'"
    context = {
        'rows':[
            ['username', 'age', 'height', 'weight'],
            ['zhiliao', '18', '180', '100']
        ]
    }
    template = loader.get_template('abc.txt')
    csv_template = template.render(context)
    response.content = csv_template
    return response

然後我們在templates資料夾下面新建一個abc.txt的檔案,寫入一下程式碼

{% for row in rows %}{{ row.0 }},{{ row.1 }},{{ row.2 }},{{ row.3 }}
{% endfor %}

注意: 這裡for後面不能換行,如果換行了之後那麼生成的csv檔案就會每寫入一行資料,就會空一行。
{% endfor %} 必須換行,否則資料將會全部顯示在一行。

生成大的CSV檔案:

以上的例子是生成的一個小的csv檔案,如果想要生成大型的csv檔案,那麼以上方式將有可能會發生超時的情況(伺服器要生成一個大型csv檔案,需要的時間可能會超過瀏覽器預設的超時時間)。這時候我們可以藉助另外一個類,叫做StreamingHttpResponse物件,這個物件是將響應的資料作為一個流返回給客戶端,而不是作為一個整體返回。示例

def large_csv_view(request):
   response = StreamingHttpResponse(content_type='text/csv')
   response['Content-Disposition'] = "attachment;filename='abc.csv'"

   rows = ("{},{}\n".format(row,row) for row in range(1,100000))
   response.streaming_content = rows
   # print(type(rows))
   # response = HttpResponse('success')
   return response

這裡我們構建了一個非常大的資料集rows,並且將其變成一個迭代器。然後因為StreamingHttpResponse的第一個引數只能是一個生成器,因此我們使用圓括號("{},{}\n".format(row,row) for row in range(1,100000))。包裹起來。

注意: StreamingHttpResponse會啟動一個程序來和客戶端保持長連線,所以會很消耗資源。所以如果不是特殊要求,儘量少用這種方法。

關於StreamingHttpResponse:

這個類是專門用來處理流資料的。使得在處理一些大型檔案的時候,不會因為伺服器處理時間過長而到時連線超時。這個類不是繼承自HttpResponse,並且跟HttpResponse對比有以下幾點區別:

  1. 這個類沒有屬性content,相反是streaming_content。
  2. 這個類的streaming_content必須是一個可以迭代的物件。
  3. 這個類沒有write方法,如果給這個類的物件寫入資料將會報錯。

想深入學習django的可以看一下這個視訊:超詳細講解Django打造大型企業官網