{% raw %}
# 使用Django輸出CSV #
這篇文檔闡述了如何通過使用Django視圖動態輸出CSV (Comma Separated Values)。 你可以使用Python CSV 庫或者Django的模板系統來達到目的。
## 使用Python CSV庫 ##
Python自帶了CSV庫,`csv`。在Django中使用它的關鍵是,`csv`模塊的CSV創建功能作用于類似于文件的對象,并且Django的`HttpResponse`對象就是類似于文件的對象。
這里是個例子:
```
import csv
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
writer = csv.writer(response)
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
return response
```
代碼和注釋是不用多說的,但是一些事情需要提醒一下:
+ 響應對象獲得了一個特殊的MIME類型,`text/csv`。這會告訴瀏覽器,文檔是個CSV文件而不是HTML文件。如果你把它去掉,瀏覽器可能會把輸出解釋為HTML,會在瀏覽器窗口中顯示一篇丑陋的、可怕的官樣文章。
+ 響應對象獲取了附加的`Content-Disposition`協議頭,它含有CSV文件的名稱。文件名可以是任意的;你想把它叫做什么都可以。瀏覽器會在”另存為“對話框中使用它,或者其它。
+ 鉤住CSV生成API非常簡單:只需要把`response`作為第一個參數傳遞給`csv.writer`。`csv.writer` 函數接受一個類似于文件的對象,而`HttpResponse` 對象正好合適。
+ 對于你CSV文件的每一行,調用`writer.writerow`,向它傳遞一個可迭代的對象比如列表或者元組。
+ CSV模板會為你處理引用,所以你不用擔心沒有轉義字符串中的引號或者逗號。只需要向`writerow()`傳遞你的原始字符串,它就會執行正確的操作。
> 在Python 2中處理Unicode
>
> Python2的`csv`模塊不支持Unicode輸入。由于Django在內部使用Unicode,這意味著從一些來源比如`HttpRequest`讀出來的字符串可能導致潛在的問題。有一些選項用于處理它:
>
> + 手動將所有Unicode對象編碼為兼容的編碼。
> + 使用[csv模塊示例章節](https://docs.python.org/library/csv.html#examples)中提供的`UnicodeWriter`類。
> + 使用[python-unicodecsv 模塊](https://github.com/jdunck/python-unicodecsv),它作為`csv`模塊隨時可用的替代方案,能夠優雅地處理Unicode。
>
> 更多信息請見`csv`模塊的Python文檔。
### 流式傳輸大尺寸CSV文件 ###
當處理生成大尺寸響應的視圖時,你可能想要使用Django的`StreamingHttpResponse`類。例如,通過流式傳輸需要長時間來生成的文件,可以避免負載均衡器在服務器生成響應的時候斷掉連接。
在這個例子中,我們利用Python的生成器來有效處理大尺寸CSV文件的拼接和傳輸:
```
import csv
from django.utils.six.moves import range
from django.http import StreamingHttpResponse
class Echo(object):
"""An object that implements just the write method of the file-like
interface.
"""
def write(self, value):
"""Write the value by returning it, instead of storing in a buffer."""
return value
def some_streaming_csv_view(request):
"""A view that streams a large CSV file."""
# Generate a sequence of rows. The range is based on the maximum number of
# rows that can be handled by a single sheet in most spreadsheet
# applications.
rows = (["Row {}".format(idx), str(idx)] for idx in range(65536))
pseudo_buffer = Echo()
writer = csv.writer(pseudo_buffer)
response = StreamingHttpResponse((writer.writerow(row) for row in rows),
content_type="text/csv")
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
return response
```
## 使用模板系統 ##
或者,你可以使用[Django模板系統](http://python.usyiyi.cn/django/topics/templates.html)來生成CSV。比起便捷的Python `csv`模板來說,這樣比較低級,但是為了完整性,這個解決方案還是在這里展示一下。
它的想法是,傳遞一個項目的列表給你的模板,并且讓模板在`for`循環中輸出逗號。
這里是一個例子,它像上面一樣生成相同的CSV文件:
```
from django.http import HttpResponse
from django.template import loader, Context
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
# The data is hard-coded here, but you could load it from a database or
# some other source.
csv_data = (
('First row', 'Foo', 'Bar', 'Baz'),
('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
)
t = loader.get_template('my_template_name.txt')
c = Context({
'data': csv_data,
})
response.write(t.render(c))
return response
```
這個例子和上一個例子之間唯一的不同就是,這個例子使用模板來加載,而不是CSV模塊。代碼的結果 -- 比如`content_type='text/csv'` -- 都是相同的。
然后,創建模板`my_template_name.txt`,帶有以下模板代碼:
```
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
{% endfor %}
```
這個模板十分基礎。它僅僅遍歷了提供的數據,并且對于每一行都展示了一行CSV。它使用了`addslashes`模板過濾器來確保沒有任何引用上的問題。
## 其它基于文本的格式 ##
要注意對于 CSV來說,這里并沒有什么特別之處 -- 只是特定了輸出格式。你可以使用這些技巧中的任何一個,來輸出任何你想要的,基于文本的格式。你也可以使用相似的技巧來生成任意的二進制數據。例子請參見[在Django中輸出PDF](http://python.usyiyi.cn/django/howto/outputting-pdf.html)。
> 譯者:[Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html),原文:[Generating CSV](https://docs.djangoproject.com/en/1.8/howto/outputting-csv/)。
>
> 本文以 [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/cn/) 協議發布,轉載請保留作者署名和文章出處。
>
> [Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html)人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606。
{% endraw %}
- 新手入門
- 從零開始
- 概覽
- 安裝
- 教程
- 第1部分:模型
- 第2部分:管理站點
- 第3部分:視圖和模板
- 第4部分:表單和通用視圖
- 第5部分:測試
- 第6部分:靜態文件
- 高級教程
- 如何編寫可重用的應用
- 為Django編寫首個補丁
- 模型層
- 模型
- 模型語法
- 元選項
- 模型類
- 查詢集
- 執行查詢
- 查找表達式
- 模型的實例
- 實例方法
- 訪問關聯對象
- 遷移
- 模式編輯器
- 編寫遷移
- 高級
- 管理器
- 原始的SQL查詢
- 聚合
- 多數據庫
- 自定義查找
- 條件表達式
- 數據庫函數
- 其它
- 遺留的數據庫
- 提供初始數據
- 優化數據庫訪問
- 視圖層
- 基礎
- URL配置
- 視圖函數
- 快捷函數
- 裝飾器
- 參考
- 內建的視圖
- TemplateResponse 對象
- 文件上傳
- 概覽
- File 對象
- 儲存API
- 管理文件
- 自定義存儲
- 基于類的視圖
- 概覽
- 內建顯示視圖
- 內建編輯視圖
- API參考
- 分類索引
- 高級
- 生成 CSV
- 生成 PDF
- 中間件
- 概覽
- 內建的中間件類
- 模板層
- 基礎
- 面向設計師
- 語言概覽
- 人性化
- 面向程序員
- 表單
- 基礎
- 概覽
- 表單API
- 內建的Widget
- 高級
- 整合媒體
- 開發過程
- 設置
- 概覽
- 應用程序
- 異常
- 概覽
- django-admin 和 manage.py
- 添加自定義的命令
- 測試
- 介紹
- 部署
- 概述
- WSGI服務器
- 部署靜態文件
- 通過email追蹤代碼錯誤
- Admin
- 管理操作
- 管理文檔生成器
- 安全
- 安全概述
- 說明Django中的安全問題
- 點擊劫持保護
- 加密簽名
- 國際化和本地化
- 概述
- 本地化WEB UI格式化輸入
- “本地特色”
- 常見的網站應用工具
- 認證
- 概覽
- 使用認證系統
- 密碼管理
- 日志
- 分頁
- 會話
- 數據驗證
- 其它核心功能
- 按需內容處理
- 重定向
- 信號
- 系統檢查框架