Djangoでcsvファイルを扱う(django-import-export)

飲食店の経費を管理するアプリを作成した際に、
過去のデータを一気に取り込む必要があった為調べると、便利なプラグインがあった。
今後株価データなどの大量のデータを管理する時にも使えそうだと思いメモ。

##開発環境
- Mac os 10.15.3
- python 3.7
- django 2.2.8

##サンプルのModel
```python:models.py
from django.db import models
from datetime import datetime


class Category(models.Model):
    category_name = models.CharField(max_length=255,unique=True)


class Shop(models.Model):
    shop_name = models.CharField(max_length=255,unique=True)
    flag = models.IntegerField(verbose_name="フラグ")
    category = models.ForeignKey(Category, on_delete = models.PROTECT, verbose_name="カテゴリ")


class Cost(models.Model):
    date = models.DateField(verbose_name="日付",default=datetime.now)
    shop = models.ForeignKey(Shop, on_delete = models.PROTECT, verbose_name="店名")
    price = models.IntegerField(verbose_name="金額", help_text="半角入力")
    memo = models.CharField(verbose_name="備考", max_length=500, blank=True)
    created_at = models.DateTimeField(verbose_name='登録日時', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新日時', auto_now=True)
```
飲食店の経費を管理するために、カテゴリー、仕入れ先、金額等と３つのモデルがあると過程。
あとはmodels.pyの通り。

##`django-import-export`のインストール
```terminal
$ pipenv install django-import-export
```
上記はpipenvを利用した場合。
pipでインストールの場合は`$ pip install django-import-export`で可能。

##settings.pyに`import_export`を追加
```python:settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # ・・・省略
    'import_export', # ここに追加
]
```
プロジェクト配下のsettings.pyのINSTALLED_APPSに`import_export`を追加

##admin.pyに設定を追加
```python:admin.py
from django.contrib import admin
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from .models import Category, Shop, Cost

# Categoryモデルに統合する為にModelResourceを継承したクラスを作成
class CategoryResource(resources.ModelResource):
    class Meta:
        model = Category

# Shopモデルに統合する為にModelResourceを継承したクラスを作成
class ShopResource(resources.ModelResource):
    class Meta:
        model = Shop

# Costモデルに統合する為にModelResourceを継承したクラスを作成
class CostResource(resources.ModelResource):
    class Meta:
        model = Cost


@admin.register(Category)
# ImportExportModelAdminを継承したadminクラスを作成
class CategoryAdmin(ImportExportModelAdmin):
    ordering = ['id']
    list_display=('id', 'category_name')

    # resource_classにModelResourceを継承したクラスを設定
    resource_class = CategoryResource


@admin.register(Shop)
# ImportExportModelAdminを継承したadminクラスを作成
class ShopAdmin(ImportExportModelAdmin):
    ordering = ['id']
    list_display=('id', 'shop_name', 'flag', 'category')

    # resource_classにModelResourceを継承したクラスを設定
    resource_class = ShopResource


@admin.register(Cost)
# ImportExportModelAdminを継承したadminクラスを作成
class CostAdmin(ImportExportModelAdmin):
    ordering = ['id']
    list_display=('id', 'date', 'shop', 'price', 'memo')

    # resource_classにModelResourceを継承したクラスを設定
    resource_class = CostResource
```
`ModelResourceを継承したクラス`と、
`ImportExportModelAdminを継承したadminクラス`を作成し、
`resource_class`に`ModelResourceを継承したクラス`を記述するだけ。
定義したリソースクラスを管理画面で使えるようにするため、
admin.pyで紐づけているって考えるとわかりやすいかも。

##任意のURL/adminにアクセス
<img width="390" alt="ss.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531099/b4fb1223-c9f0-d1f6-d30e-2df244747949.png">
画像のようにインポートとエクスポートボタンが表示される。
実際にインポートとエクスポートがこれで可能。

<img width="591" alt="ss 1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531099/7f7a1c32-d315-8da3-88f9-f60559f7e8b6.png">

ちなみに`csv`以外にも、`xls`、`xlsx`、`tsv`、`json`、`yaml`にも対応している。
意外と便利。しかし、データが多くなると処理速度が少し遅い気がする。。。

##参考にしたサイト
https://qiita.com/kira_puka/items/14a1a604a428a4c68884
https://django-import-export.readthedocs.io/en/stable/index.html