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