SQLの実行結果をCSVとしてエクスポートさせることは多々あるんですが、
その件数結果が多すぎてタイムアウトが発生したとか、メモリを使いすぎてwebサーバが爆発した……ということも稀にあったりします。
ので、少しずつ取得しつつ結果をcsvとして出力する方法を備忘録も兼ねて。
準備するもの!
class Echo(object):
def write(self, value):
return value
def yield_query(query):
filter_id = 0
while True:
rows = list(query.filter(id__gt=filter_id).order_by('id')[:1000])
if len(rows) == 0:
break
for row in rows:
yield row
filter_id = rows[-1].id
def stream_csv_response(rows):
writer = csv.writer(Echo())
response = StreamingHttpResponse(
(writer.writerow(row) for row in rows),
content_type="text/csv"
)
response['Content-Disposition'] = 'attachment; filename="big.csv"'
return response
- yield_queryは、渡されたqueryを少しずつ実行していく関数です。
- stream_csv_responseは、yield_queryの実行結果を引数rowsで受け取り、Djangoのresponseを返してあげる関数です。
呼び方!
# 適当なModelを用意
test_query = Test.objects
# yieldを返すobjectを取得
yield_rows = yield_query(test_query)
# レスポンスの返却
return stream_csv_response(yield_rows)
ね、簡単でしょ?