Django で CSV を出力する
| revision-up-to: | 5613 (0.97pre SVN) |
|---|
このドキュメントでは, Django のビューを使って動的に CSV (Comma Separated Values: カンマ区切りのフィールドデータ) ファイルを生成する方法について説明 します.
CSV の生成には Python CSV ライブラリ , または Django テンプレートシ ステムが必要です.
CSV ライブラリを使う
Python には CSV ライブラリモジュール csv がついてきます.Django で csv を使う上での鍵は,モジュールの CSV 生成機能がファイルライクオ ブジェクトを扱えることと, Django の HttpResponse オブジェクトがファイ ルライクオブジェクトであることにあります.
Note
HttpResponse オブジェクトの詳細は リクエストオブジェクトとレスポンスオブジェクト を参照してください.
CSV ライブラリの詳細は CSV ライブラリのドキュメント を参照してくださ い.
一例を示します:
import csv
from django.http import HttpResponse
def some_view(request):
# 適切な CSV 用ヘッダとともに HttpResponse オブジェクトを生成します.
response = HttpResponse(mimetype='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 であると指示します. MIME タイプを指定し ないと,出力を HTML として解釈するので,ブラウザウィンドウに見苦しい ごみのような出力が表示されてしまいます.
- さらに,レスポンスオブジェクトには Content-Disposition ヘッダを指 定しています.このヘッダは CSV ファイルの名前にします.ファイル名には 何を指定しても構いません.この名前は,ブラウザが「名前を付けて保存」 ダイアログなどで使います.
- CSV 生成 API のフックは簡単です: response を csv.writer の第 一引数に指定します. csv.writer クラスはファイルライクオブジェク トを扱うようになっているので, HttpResponse オブジェクトを使えま す.
- CSV ファイルの各行ごとにリストやタプルのようなイテレーション可能オブ ジェクトを渡して writer.writerow を呼び出します.
- CSV モジュールはクオート処理を行ってくれるので,文字列中にクオートや カンマがあっても心配することはありません.出力したい値を writerow() に渡せば,モジュールが正しく処理してくれます.
テンプレートシステムを使う
csv を使う代りに Django テンプレートシステム を使っても CSV を生成で きます.この方法よりも csv モジュールを使った方がより高水準で実現できま すが,完全さのために紹介しておきます.
基本的な考え方は,テンプレートに要素リストを渡し,テンプレート上の {% for %} ループの中でコンマとともに出力するというものです.
上と同じ CSV ファイルを生成する例を示します:
from django.http import HttpResponse
from django.core.template import loader, Context
def some_view(request):
# 適切な CSV 用応答ヘッダを持った HttpResponse オブジェクトを
# 作成します.
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=somefilename.csv'
# ここではデータをハードコードしていますが,実際にはデータベースな
# のデータソースから取り出せます.
csv_data = (
('First row', 'Foo', 'Bar', 'Baz'),
('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
)
t = loader.get_template('my_template_name.html')
c = Context({
'data': csv_data,
})
response.write(t.render(c))
return response
前節の例との違いは, CSV モジュールの代りにテンプレートをロードしている点だ けです.それ以外のコード,例えば mimetype='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 テンプレートフィルタ を使っています.データに引用符 (一重と二 重の両方) が入っていないと保証できる場合は addslashes フィルタを外して もかまいません.