Posted at

【Python3】Djangoで登録されたデータをCSV出力する

More than 1 year has passed since last update.


はじめに

Python(Django)でWebアプリケーション作ってると、「データをCSVで出せるようにしてほしい」という要望はほぼマストなので備忘録的にまとめます。


CSVファイルを生成する

例えば毎月1日に、前月の受注リストなんかを集計してその結果をCSVとして出力する、という動作を考えます。

ファイル名は yymm_billing.csv という命名規則とします。

また、クライアントはWindows端末のExcelでCSVを閲覧することを想定し、文字化けさせないために出力するCSVの文字コードを cp932 とする。

Order テーブルは以下のように定義する。


models.py

class Order(models.Model):

order_date = models.DateField("受注日", auto_now=False, auto_now_add=False, default=date.today)
customer = models.CharField("顧客名", max_length=255)
phone_number = models.CharField("電話番号", max_length=255)
item = models.CharField("商品名", max_length=255)
num = models.IntegerField("数量", null=True, blank=True)
cost = models.IntegerField("原価", null=True, blank=True)
earnings = models.IntegerField("売上", null=True, blank=True)
gross_profit = models.IntegerField("粗利", null=True, blank=True)

で、実際のCSV出力の処理ですが、結構長くなってしまった。

日付の計算をするために relativedelta を利用しているので

pip install python-dateutil

でインストールしておきます。


output_csv.py

from datetime import datetime, date, time, timedelta

from dateutil.relativedelta import relativedelta
from myapp.models import Order # モデルは適当です
import csv

"""
例えば2018年10月1日にこのスクリプトを実行すると
/path/to/output_dir に
201810_billing.csv
というファイルが生成されるようにする。
"""

t = date.today()
output_path = '/path/to/output_dir'
output_name = t.strftime('%Y%m') + '_billing.csv'

# 検索対象レコードの抽出
start_date = date.today().replace(day=1) - relativedelta(months=1) # 前月の1日を取得
end_date = date.today().replace(day=1) - timedelta(1) # 前月の最終日を取得

order_list = Order.objects.filter(order_date__gte=start_date)\
.filter(order_date__lte=end_date)

# CSV出力処理開始
with open(output_path + output_name, 'w', encoding='cp932', newline='') as csv_file:
# 1行目にヘッダーを書き込む
header = ['受注日時', '顧客名', '電話番号', '商品名', '数量', '原価', '売上', '粗利']
writer = csv.writer(csv_file, quoting=csv.QUOTE_ALL)
writer.writerow(header)

for order in order_list:
order_date = order.order_date
customer = order.customer
phone_number = order.phone_number
item = order.item
num = order.num
cost = order.cost
earnings = order.earnings
gross_profit = order.gross_profit

row = []
row += [order_date, customer, phone_number, item, num, cost, earnings, gross_profit]

writer.writerow(row)


これで対象のディレクトリに定義した命名規則のCSVが吐き出されるようになります。

あとはダウンロードボタンを作ってあげてファイルをダウンロードできるようにしてあげればOKです。

モデルの定義などはこの記事を書くために適当に用意したものなのであまり参考にしないようお願いします。