くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Django/PythonでCSVファイルをアップロード(.csv)したり、ダウンロード(.csv)したり、ダウンロード(.zip)したりする方法

Django/Pytonを使ってCSVファイルをあれこれするために、いろいろ調べたので、その際の備忘録。

環境はDjango1.10.1とPython2.7

CSVファイルの扱いは、基本的にimport csvのパッケージ

okadateさんのQiita記事にあるとおり、PythonでのCSVファイルの操作は以下な感じ。

import csv

# 読み込み
with open('some.csv', 'r') as f:
  reader = csv.reader(f)
  header = next(reader)  # ヘッダーを読み飛ばしたい時
  for row in reader:
    print row          # 1行づつ取得できる

# 書き込み
with open('some.csv', 'w') as f:
  writer = csv.writer(f, lineterminator='\n') # 改行コード(\n)を指定しておく
  writer.writerow(list)     # list(1次元配列)の場合
  writer.writerows(array2d) # 2次元配列も書き込める

Django上でこれらを行うときは、リクエストとレスポンスも絡んでくる。

アップロードされたCSVファイルを読み込んで処理する

アップロードされたCSVファイルを読み込む場合は、open()request.FILES['file']になる感じ。

import csv
import traceback
from django.shortcuts import render

def upload_file(request):
  try:
    csv_file = request.FILES['file']

    reader = csv.reader(req_file)
    header = next(reader)

    for csv_row in reader:
      print csv_row 

    csv_file .close()
  except:
    traceback.format_exc()

  return render(request, "index.html")

CSVファイルをダウンロードする

基本的には、csv.writerを使って、`responseに書き込んでいく感じ。
ただ、日本語の場合は、ファイル名とファイルの中身の文字コードに注意!!

  • ファイル名が日本語の場合、UTF8でURLエンコードする
  • ファイルの中身が日本語の場合、環境に合わせる。(例はWindows用としてSJISに変換)
import csv
import urllib
from django.http.response import HttpResponse

def download_csv(request):
  filename = urllib.quote((u'CSVファイル.csv').encode("utf8"))

  response = HttpResponse(content_type='text/csv')  
  response['Content-Disposition'] = 'attachment; filename*=UTF-8\'\'{}'.format(filename)

  writer = csv.writer(response)

  writer.writerow(map(lambda n:toSJIS(n), [u'概要', u'詳細']))
  writer.writerow(map(lambda n:toSJIS(n), [u'ああああ', u'いいい']))
  writer.writerow(map(lambda n:toSJIS(n), [u'かかかか', u'ききき']))

  return response

def toSJIS(s=""):
  u'{}'.format(s).encode("sjis")

複数のCSVファイルをzipにまとめてダウンロードする

こちらも基本はcsv.writerを使ってzip_fileに書き込み、zip_fileの内容をresponseに設定する感じ。
注意点はこちらも文字コード周り。。。

  • ZIPファイル名が日本語の場合、UTF8でURLエンコードする
  • CSVファイル名が日本語の場合、環境に合わせる。URLエンコードは不要(例はWindows用としてSJISに変換)
  • CSVファイルの中身が日本語の場合、環境に合わせる。(例はWindows用としてSJISに変換)
import csv
import urllib
import zipfile
from django.http.response import HttpResponse

def download_csv_zip(request):
  #### 書き込むzipファイルの準備
  memory_file = BytesIO()
  zip_file = zipfile.ZipFile(memory_file, 'w')

  #### CSVファイルの書き込み。1ファイル目
  csv_file1 = BytesIO()
  filename1 = (u'CSVファイル1.csv').encode("sjis")
  writer1 = csv.writer(csv_file1)

  writer1.writerow(map(lambda n:toSJIS(n), [u'概要', u'詳細']))
  writer1.writerow(map(lambda n:toSJIS(n), [u'ああああ', u'いいい']))

  ## CSVファイルの内容をzip_fileに書き込む。
  zip_file.writestr(filename1, csv_file1.getvalue())
  csv_file1.close()

  #### CSVファイルの書き込み。2ファイル目
  csv_file2 = BytesIO()
  filename2 = (u'CSVファイル2.csv').encode("sjis")
  writer2 = csv.writer(csv_file2)

  writer2.writerow(map(lambda n:toSJIS(n), [u'概要', u'詳細']))
  writer2.writerow(map(lambda n:toSJIS(n), [u'ああああ', u'いいい']))

  ## CSVファイルの内容をzip_fileに書き込む。
  zip_file.writestr(filename2, csv_file2.getvalue())
  csv_file2.close()
  

  #### zipファイルの内容をreponseに設定
  zip_file.close()
  zip_filename = urllib.quote((u'CSVファイル(複数).zip').encode("utf8"))
  response = HttpResponse(memory_file.getvalue(), content_type='application/zip')
  response['Content-Disposition'] = 'attachment; filename*=UTF-8\'\'{}'.format(urllib.quote(zip_file_name))

  return response

def toSJIS(s=""):
  u'{}'.format(s).encode("sjis")

以上!!

Python、さくっと書くのはいいんだけど、静的型付け言語が好きなので、結構困る。。。

参考にしたサイト様