# 第五節:生成CSV文件
# 生成CSV文件:
有時候我們做的網站,需要將一些數據,生成有一個`CSV`文件給瀏覽器,并且是作為附件的形式下載下來。以下將講解如何生成`CSV`文件。
## 生成小的CSV文件:
這里將用一個生成小的`CSV`文件為例,來把生成`CSV`文件的技術要點講到位。我們用`Python`內置的`csv`模塊來處理`csv`文件,并且使用`HttpResponse`來將`csv`文件返回回去。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">import</span> csv
<span class="hljs-keyword">from</span> django.http <span class="hljs-keyword">import</span> HttpResponse
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">csv_view</span><span class="hljs-params">(request)</span>:</span>
response = HttpResponse(content_type=<span class="hljs-string">'text/csv'</span>)
response[<span class="hljs-string">'Content-Disposition'</span>] = <span class="hljs-string">'attachment; filename="somefilename.csv"'</span>
writer = csv.writer(response)
writer.writerow([<span class="hljs-string">'username'</span>, <span class="hljs-string">'age'</span>, <span class="hljs-string">'height'</span>, <span class="hljs-string">'weight'</span>])
writer.writerow([<span class="hljs-string">'zhiliao'</span>, <span class="hljs-string">'18'</span>, <span class="hljs-string">'180'</span>, <span class="hljs-string">'110'</span>])
<span class="hljs-keyword">return</span> response
```
```
這里再來對每個部分的代碼進行解釋:
1. 我們在初始化`HttpResponse`的時候,指定了`Content-Type`為`text/csv`,這將告訴瀏覽器,這是一個`csv`格式的文件而不是一個`HTML`格式的文件,如果用默認值,默認值就是`html`,那么瀏覽器將把`csv`格式的文件按照`html`格式輸出,這肯定不是我們想要的。
2. 第二個我們還在`response`中添加一個`Content-Disposition`頭,這個東西是用來告訴瀏覽器該如何處理這個文件,我們給這個頭的值設置為`attachment;`,那么瀏覽器將不會對這個文件進行顯示,而是作為附件的形式下載,第二個`filename="somefilename.csv"`是用來指定這個`csv`文件的名字。
3. 我們使用`csv`模塊的`writer`方法,將相應的數據寫入到`response`中。
## 將`csv`文件定義成模板:
我們還可以將`csv`格式的文件定義成模板,然后使用`Django`內置的模板系統,并給這個模板傳入一個`Context`對象,這樣模板系統就會根據傳入的`Context`對象,生成具體的`csv`文件。示例代碼如下:
模板文件:
```
<pre class="calibre12">```
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
{% endfor %}
```
```
視圖函數:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.http <span class="hljs-keyword">import</span> HttpResponse
<span class="hljs-keyword">from</span> django.template <span class="hljs-keyword">import</span> loader, Context
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">some_view</span><span class="hljs-params">(request)</span>:</span>
response = HttpResponse(content_type=<span class="hljs-string">'text/csv'</span>)
response[<span class="hljs-string">'Content-Disposition'</span>] = <span class="hljs-string">'attachment; filename="somefilename.csv"'</span>
csv_data = (
(<span class="hljs-string">'First row'</span>, <span class="hljs-string">'Foo'</span>, <span class="hljs-string">'Bar'</span>, <span class="hljs-string">'Baz'</span>),
(<span class="hljs-string">'Second row'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-string">'C'</span>, <span class="hljs-string">'"Testing"'</span>, <span class="hljs-string">"Here's a quote"</span>),
)
t = loader.get_template(<span class="hljs-string">'my_template_name.txt'</span>)
response.write(t.render({<span class="hljs-string">"data"</span>: csv_data}))
<span class="hljs-keyword">return</span> response
```
```
## 生成大的CSV文件:
以上的例子是生成的一個小的`csv`文件,如果想要生成大型的`csv`文件,那么以上方式將有可能會發生超時的情況(服務器要生成一個大型csv文件,需要的時間可能會超過瀏覽器默認的超時時間)。這時候我們可以借助另外一個類,叫做`StreamingHttpResponse`對象,這個對象是將響應的數據作為一個流返回給客戶端,而不是作為一個整體返回。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Echo</span>:</span>
<span class="hljs-string">"""
定義一個可以執行寫操作的類,以后調用csv.writer的時候,就會執行這個方法
"""</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">write</span><span class="hljs-params">(self, value)</span>:</span>
<span class="hljs-keyword">return</span> value
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">large_csv</span><span class="hljs-params">(request)</span>:</span>
rows = ([<span class="hljs-string">"Row {}"</span>.format(idx), str(idx)] <span class="hljs-keyword">for</span> idx <span class="hljs-keyword">in</span> range(<span class="hljs-params">655360</span>))
pseudo_buffer = Echo()
writer = csv.writer(pseudo_buffer)
response = StreamingHttpResponse((writer.writerow(row) <span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> rows),content_type=<span class="hljs-string">"text/csv"</span>)
response[<span class="hljs-string">'Content-Disposition'</span>] = <span class="hljs-string">'attachment; filename="somefilename.csv"'</span>
<span class="hljs-keyword">return</span> response
```
```
這里我們構建了一個非常大的數據集`rows`,并且將其變成一個迭代器。然后因為`StreamingHttpResponse`的第一個參數只能是一個生成器,因此我們使用圓括號`(writer.writerow(row) for row in rows)`,并且因為我們要寫的文件是`csv`格式的文件,因此需要調用`writer.writerow`將`row`變成一個`csv`格式的字符串。而調用`writer.writerow`又需要一個中間的容器,因此這里我們定義了一個非常簡單的類`Echo`,這個類只實現一個`write`方法,以后在執行`csv.writer(pseudo_buffer)`的時候,就會調用`Echo.writer`方法。
注意:`StreamingHttpResponse`會啟動一個進程來和客戶端保持長連接,所以會很消耗資源。所以如果不是特殊要求,盡量少用這種方法。
## 關于StreamingHttpResponse:
這個類是專門用來處理流數據的。使得在處理一些大型文件的時候,不會因為服務器處理時間過長而到時連接超時。這個類不是繼承自`HttpResponse`,并且跟`HttpResponse`對比有以下幾點區別:
1. 這個類沒有屬性`content`,相反是`streaming_content`。
2. 這個類的`streaming_content`必須是一個可以迭代的對象。
3. 這個類沒有`write`方法,如果給這個類的對象寫入數據將會報錯。
注意:`StreamingHttpResponse`會啟動一個進程來和客戶端保持長連接,所以會很消耗資源。所以如果不是特殊要求,盡量少用這種方法。
- Introduction
- 第一章:學前準備
- 第一節:虛擬環境
- 第二節:準備工作
- 第三節:Django介紹
- 第四節:URL組成部分
- 第二章:URL與視圖
- 第一節:第一個Django項目
- 第二節:視圖與URL分發器
- 第三章:模板
- 第一節:模板介紹
- 第二節:模板變量
- 第三節:常用標簽
- 第四節:常用過濾器
- 第五節:自定義過濾器
- 第七節:模版結構優化
- 第八節:加載靜態文件
- 第四章:數據庫
- 第一節:MySQL相關軟件
- 第二節:數據庫操作
- 第三節:ORM模型
- 第四節:模型常用字段
- 第五節:外鍵和表關系
- 第六節:增刪改查操作
- 第七節:查詢操作
- 第八節:QuerySet API
- 第九節:ORM模型遷移
- 第十節:ORM作業
- 第十一節:ORM作業參考答案
- 第十二節:Pycharm連接數據庫
- 第五章:視圖高級
- 第一節:限制請求method
- 第二節:頁面重定向
- 第三節:HttpRequest對象
- 第四節:HttpResponse對象
- 第五節:生成CSV文件
- 第六節:類視圖
- 第七節:錯誤處理
- 第六章:表單
- 第一節:表單概述
- 第二節:用表單驗證數據
- 第三節:ModelForm
- 第四節:文件上傳
- 第七章:cookie和session
- 第八章:上下文處理器和中間件
- 第一節:上下文處理器
- 第二節:中間件
- 第九章:安全
- 第一節:CSRF攻擊
- 第二節:XSS攻擊
- 第三節:點擊劫持攻擊
- 第四節:SQL注入
- 第十章:信號
- 第一節:什么是信號
- 第十一章:驗證和授權
- 第一節:概述
- 第二節:用戶對象
- 第三節:權限和分組
- 第十二章:Admin系統
- 第十三章:Django的緩存
- 第十四章:memcached
- 第十五章:Redis