ブログBLOG

\ Web・ゲーム開発に関する情報を発信中 /

【超簡単】CSVを利用してDjangoのデータベースにデータをインポートする方法

Django
csv , django , python
20250131_django-import-database-from-csv-tmb

ご覧いただきありがとうございます!
領護(りょうご)です。

Djangoのデータベースに一つずつデータを登録するのは面倒…。
そんな時はCSVを使って一括インポートしたいですよね!
今回は、CSVを利用してDjangoのデータベースにデータをインポートする方法を解説します。


CSVのデータをデータベースにインポートする画像1


CSVのデータをデータベースにインポートする画像2
上記のように、CSVをアップロードするフォームを用意し、登録ボタンをクリックするだけで、Djangoのデータベースにデータを一括インポートできます。

目次

実行環境

Docker Desktop:4.38.0
Python:3.12.8
Django:5.1.3
Pandas:2.2.3

フォルダ構成

sample_web/
├── .env                    # 環境変数ファイル
├── requirements.txt        # インストールするPythonライブラリの一覧
├── docker-compose.yml      # Docker Compose設定ファイル
├── manage.py               # Django管理スクリプト
├── sample_project/         # プロジェクト名
│   ├── asgi.py             # ASGI設定ファイル
│   ├── settings.py         # プロジェクト設定ファイル
│   ├── urls.py             # URLルーティング
│   ├── wsgi.py             # WSGI設定ファイル
│   ├── static/             # 静的ファイルディレクトリ
│   │   └── css/
│   │       └── base.css    # ベースCSSファイル
│   └── templates/          # HTMLテンプレートディレクトリ
│       └── sample.html     # ダウンロードページのテンプレート
├── home/                   # アプリフォルダ
│   ├── admin.py            # 管理サイト用の設定ファイル
│   ├── forms.py            # フォーム定義ファイル
│   ├── models.py           # モデル定義ファイル
│   ├── urls.py             # URLルーティング
│   ├── views.py            # ビューファイル
│   └── migrations/         # マイグレーションファイル

今回の解説では、上記のフォルダ構成を使用します。
主に使用するのは、requirements.txt、home/admin.py、home/forms.py、home/models.py、home/urls.py、home/views.py、templates/sample.htmlの7つのファイルです。

必要なライブラリのインストール

pip install pandas

データを扱いやすくするためのライブラリ「pandas」をインストールします。

requirements.txt
pandas

requirements.txtを使用する場合は、「pandas」を追記してインストールしてください。

モデル定義を作成

まず初めに、例として使用する従業員モデルをhome/models.pyに作成します。
※ 既にモデルを作成済みの場合は、CSVアップロードフォームの作成までスキップしてください。

models.py
from django.db import models
from django.utils.translation import gettext_lazy as _

# 従業員モデル
class Employee(models.Model):

    # 氏名
    employee_name = models.CharField(verbose_name=_("氏名"), max_length=32)

    # 所属名
    organization_name = models.CharField(verbose_name=_("所属名"), max_length=32)

    # 年齢
    age = models.PositiveIntegerField(verbose_name=_("年齢"))

    # 作成日時
    created_at = models.DateTimeField(verbose_name=_("作成日時"), auto_now_add=True)

    class Meta:
        db_table = "employees"
        verbose_name = _("従業員")
        verbose_name_plural = _("従業員")

    def __str__(self):
        return self.employee_name

ID(自動付与)、氏名、所属名、年齢、作成日時の5つのフィールドを作成しています。

Django管理画面に表示

Djangoの管理画面に従業員モデルを表示する設定をhome/admin.pyに作成します。

admin.py
from django.contrib import admin
from .models import *

# 従業員モデル管理画面
class EmployeeAdmin(admin.ModelAdmin):
    list_display = (
        "id",
        "employee_name",
        "organization_name",
        "age",
        "created_at",
    )

# Django管理画面に表示する
admin.site.register(Employee, EmployeeAdmin)

ここまで完成したら、makemigrationsとmigrateを行います。
次に、CSVアップロードフォームを作成します。

CSVアップロードフォームの作成

CSVファイルをアップロードするフォームをhome/forms.pyに作成します。
forms.pyファイルがない場合は、ご自身で新規作成をしてください。

forms.py
import os
from django import forms

# CSVアップロードフォーム
class CSVUploadForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    csv_file = forms.FileField(label="CSVファイルアップロード")

    # 拡張子バリデーション
    def clean_csv_file(self):
        file = self.cleaned_data["csv_file"]
        extension = os.path.splitext(file.name)[1]
        if not extension.lower() in ".csv":
            raise forms.ValidationError("csvファイルを選択してください")
        return file

CSVファイルをアップロードするフォーム 「CSVUploadForm」 を作成しました。
さらに、CSVファイルの拡張子のみ許可するように、cleanバリデーション関数も実装しています。
続いて、CSVのデータをデータベースに保存する機能を作成します。

CSVのデータをデータベースに保存する機能をビューに作成

CSVのデータをデータベースに保存する機能をhome/views.pyに作成します。

views.py
import pandas as pd
from django.views.generic import FormView
from django.contrib import messages
from django.shortcuts import redirect
from .forms import CSVUploadForm
from .models import Employee

# サンプルページ
class SamplePage(FormView):

    template_name = "sample.html"
    form_class = CSVUploadForm
    model = Employee

    # 従業員一覧を表示(なくてもOK)
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["employees"] = self.model.objects.all()
        return ctx

    # CSVからDBに保存する処理
    def form_valid(self, form):

        # データ登録用配列
        register_list = []

        # スキップする行数を指定
        SKIP_ROWS = 1

        # カラム名を指定
        COLUMNS = [
            "id",
            "employee_name",
            "organization_name",
            "age",
        ]

        # 文字コードを指定
        ENCODING = "utf-8-sig"

        # CSVからデータをdf形式で取得
        csv_file = form.cleaned_data["csv_file"]
        df = pd.read_csv(
            csv_file,
            skiprows=SKIP_ROWS,
            names=COLUMNS,
            usecols=COLUMNS,
            encoding=ENCODING,
        )

        # 欠損値を空白に置換
        df = df.fillna("")

        # データを1行ずつ取得
        for row in df.itertuples():

            # 未入力の行はスキップ(氏名, 所属名, 年齢を指定)
            if not row.employee_name or not row.organization_name or not row.age:
                continue

            # モデルのフィールド名別にデータを格納
            create_dict = {
                "employee_name": row.employee_name,
                "organization_name": row.organization_name,
                "age": row.age,
            }

            # データ保存候補に追加
            register_list.append(self.model(**create_dict))

        # DBにデータを保存する処理
        if register_list:

            # データを一括保存
            self.model.objects.bulk_create(register_list)
            messages.success(self.request, f"DBにデータ登録が完了しました。")

        return redirect("sample_page")

CSVのデータをデータベースに保存する機能全体のプログラムです。
詳しく解説しますね。

views.py
import pandas as pd
from django.views.generic import FormView
from django.contrib import messages
from django.shortcuts import redirect
from .forms import CSVUploadForm
from .models import Employee

必要なライブラリをインポートしています。
modelsは、ご自身が用意したモデルをインポートしてください。
formsは、先ほど作成したCSVをアップロードするフォームをインポートしてください。

views.py
template_name = "sample.html"
form_class = CSVUploadForm
model = Employee

以下のように指定しています。
template_name : 今回使用するCSVアップロードページのHTML(後に作成)
form_class : CSVアップロード用のフォームクラス(先ほど作成したCSVUploadFormを指定)
model : データを保存するモデル

views.py
# 従業員一覧を表示(なくてもOK)
def get_context_data(self, **kwargs):
    ctx = super().get_context_data(**kwargs)
    ctx["employees"] = self.model.objects.all()
    return ctx

従業員全データを画面に表示するコードです。
※ データの登録確認に使用するため、なくても問題ありません。

views.py
# CSVからDBに保存する処理
def form_valid(self, form):

    # データ登録用配列
    register_list = []

    # スキップする行数を指定
    SKIP_ROWS = 1

    # カラム名を指定
    COLUMNS = [
        "id",
        "employee_name",
        "organization_name",
        "age",
    ]

    # 文字コードを指定
    ENCODING = "utf-8-sig"

    # CSVからデータをdf形式で取得
    csv_file = form.cleaned_data["csv_file"]
    df = pd.read_csv(
        csv_file,
        skiprows=SKIP_ROWS,
        names=COLUMNS,
        usecols=COLUMNS,
        encoding=ENCODING,
    )

    # 欠損値を空白に置換
    df = df.fillna("")

    # データを1行ずつ取得
    for row in df.itertuples():

        # 未入力の行はスキップ(氏名, 所属名, 年齢を指定)
        if not row.employee_name or not row.organization_name or not row.age:
            continue

        # モデルのフィールド名別にデータを格納
        create_dict = {
            "employee_name": row.employee_name,
            "organization_name": row.organization_name,
            "age": row.age,
        }

        # データ保存候補に追加
        register_list.append(self.model(**create_dict))

    # DBにデータを保存する処理
    if register_list:

        # データを一括保存
        self.model.objects.bulk_create(register_list)
        messages.success(self.request, f"DBにデータ登録が完了しました。")

    return redirect("sample_page")

CSVのデータをデータベースに保存する主要コードです。

views.py
# スキップする行数を指定
SKIP_ROWS = 1

# カラム名を指定
COLUMNS = [
    "id",
    "employee_name",
    "organization_name",
    "age",
]

# 文字コードを指定
ENCODING = "utf-8-sig"

「SKIP_ROWS」は、CSVファイルを読み込む際にスキップする行数を指定します。
今回使用するCSVファイルは1行目に見出しを含んでいるため、1行目をスキップする設定にしています。

「COLUMNS」は、読み込む列の数と列名を指定します。
列名には、対応するモデルのフィールド名を指定すると分かりやすくなります。

「ENCODING」は、CSVファイルの文字コードを指定します。
今回は「UTF-8」を指定しています。

20250131_django-import-database-from-csv-03

注意!

もし上記のようなエラーが発生する場合は、指定した文字コードが正しくない可能性があります。
CSVファイルの文字コードを確認し、適切な文字コードを指定してください。

views.py
# CSVからデータをdf形式で取得
csv_file = form.cleaned_data["csv_file"]
df = pd.read_csv(
    csv_file,
    skiprows=SKIP_ROWS,
    names=COLUMNS,
    usecols=COLUMNS,
    encoding=ENCODING,
)

# 欠損値を空白に置換
df = df.fillna("")

フォームから取得したCSVファイルを、先ほど指定したパラメーターを適用し、pandasを使って読み込みます。
また、データに欠損があった場合は、欠損値(NaN)を空白に置換するように設定しています。

views.py
# データを1行ずつ取得
for row in df.itertuples():

    # 未入力の行はスキップ(氏名, 所属名, 年齢を指定)
    if not row.employee_name or not row.organization_name or not row.age:
        continue

    # モデルのフィールド名別にデータを格納
    create_dict = {
        "employee_name": row.employee_name,
        "organization_name": row.organization_name,
        "age": row.age,
    }

    # データ保存候補に追加
    register_list.append(self.model(**create_dict))

# DBにデータを保存する処理
if register_list:

    # 配列からデータを一括保存
    self.model.objects.bulk_create(register_list)
    messages.success(self.request, f"DBにデータ登録が完了しました。")

return redirect("sample_page")

CSVのデータをデータベースにインポートする主要な処理部分は、以下の手順で行っています。

  1. 読み込んだCSVのデータを1行ずつ取り出します。
  2. 氏名、所属名、年齢が全て入力済みか確認し、どれか一つでも未入力があればその行をスキップします。
  3. モデルのフィールド名ごとにデータを格納する辞書を作成します。
  4. データベースに保存するための配列に辞書データを追加します。
  5. 格納した配列を 「bulk_create」 関数を使用して、データベースに一括登録します。
  6. 処理が完了したら、CSVアップロードフォームページにリダイレクトします。
views.py
# モデルのフィールド名別にデータを格納
create_dict = {
    "employee_name": row.employee_name,
    "organization_name": row.organization_name,
    "age": row.age,
}

今回は、氏名、所属名、年齢のみをCSVからデータを取得して保存します。
IDと作成日時は自動でデータが追加されるため、含めていません。

urls.pyを作成

ビューを表示するためにhome/urls.pyも作成しておきます。

urls.py
from django.urls import path
from . import views

urlpatterns = [
    path(
        "",
        views.SamplePage.as_view(),
        name="sample_page",
    ),
]

以上で、CSVのデータをデータベースに保存する機能の作成が完了しました。
次に、CSVアップロードフォームと登録ボタンの設置、そしてモデルデータを確認するためのコードを作成します。

CSVアップロードフォームと登録ボタンの設置とモデルデータ確認画面の作成

CSVアップロードフォームと登録ボタンの設置とモデルデータ確認画面をtemplates/sample.htmlに作成します。

sample.html
{% load static %}
<!DOCTYPE html>
<html lang="ja">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}">
    <title>CSVファイルからDBにデータを保存するページ</title>
  </head>

  <body>
    <main>
      <h1>CSVファイルからDBにデータを保存するページ</h1>
      <section>
        <h2>CSVアップロードフォーム</h2>
        <form class="form" action="" method="POST" enctype="multipart/form-data">
          {% csrf_token %}
          {{ form.csv_file }}
          <!-- 成功メッセージを表示 -->
          <div class="success">
            {% for message in messages %}
              {{ message }}
            {% endfor %}
          </div>
          <!-- エラーメッセージを表示 -->
          <div class="error">
            {% if form.csv_file.errors %}
              {{ form.csv_file.errors }}
            {% endif %}
          </div>
          <button type="submit">CSVからデータをDBに登録する</button>
        </form>
      </section>

      <!-- ここのsectionは無くてもOK -->
      <section>
        <h2>従業員一覧を表示</h2>
        <table>
          <thead>
            <tr>
              <th>ID</th>
              <th>氏名</th>
              <th>所属名</th>
              <th>年齢</th>
              <th>作成日時</th>
            </tr>
          </thead>
          <tbody>
            {% for employee in employees %}
              <tr>
                <td>{{ employee.id }}</td>
                <td>{{ employee.employee_name }}</td>
                <td>{{ employee.organization_name }}</td>
                <td>{{ employee.age }}</td>
                <td>{{ employee.created_at }}</td>
              </tr>
            {% endfor %}
          </tbody>
        </table>
      </section>
    </main>
  </body>
</html>

CSVアップロードフォームと登録ボタンの設置とモデルデータ確認画面全体のプログラムです。
詳しく解説しますね。

sample.html
<section>
    <h2>CSVアップロードフォーム</h2>
    <form class="form" action="" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form.csv_file }}
        <!-- 成功メッセージを表示 -->
        <div class="success">
        {% for message in messages %}
            {{ message }}
        {% endfor %}
        </div>
        <!-- エラーメッセージを表示 -->
        <div class="error">
        {% if form.csv_file.errors %}
            {{ form.csv_file.errors }}
        {% endif %}
        </div>
        <button type="submit">CSVからデータをDBに登録する</button>
    </form>
</section>

CSVをアップロードするフォームと登録ボタンを表示します。
アップロード成功時と失敗時のメッセージも表示できるようにしています。
※ 必須ではありませんが、あったほうが親切ですね!

注意!

ファイルをアップロードする際は、form タグに必ず「enctype="multipart/form-data"」を指定してください。良く忘れがちなので、注意しましょう!

sample.html
<!-- ここのsectionは無くてもOK -->
<section>
    <h2>従業員一覧を表示</h2>
    <table>
        <thead>
        <tr>
            <th>ID</th>
            <th>氏名</th>
            <th>所属名</th>
            <th>年齢</th>
            <th>作成日時</th>
        </tr>
        </thead>
        <tbody>
        {% for employee in employees %}
            <tr>
            <td>{{ employee.id }}</td>
            <td>{{ employee.employee_name }}</td>
            <td>{{ employee.organization_name }}</td>
            <td>{{ employee.age }}</td>
            <td>{{ employee.created_at }}</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
</section>

CSVから登録した従業員の全データを表示します。
※ データが正しくインポートされたか確認するためのコードなので、なくても問題ありません。

これでCSVアップロードフォームと登録ボタンの設置、そしてモデルデータ確認画面が完成しました!
実際に動作を確認してみます。

CSVのデータをデータベースに保存する動作確認

20250131_django-import-database-from-csv-04

今回は、このような従業員CSVデータをデータベースにインポートしてみます。

20250131_django-import-database-from-csv-01
  1. データベースに登録したいCSVファイルをアップロードフォームから選択します。
  2. 「CSVからデータをDBに登録する」ボタンをクリックします。
20250131_django-import-database-from-csv-02

データベースにインポートが完了し、従業員一覧にもデータが表示されました!
また、「DBにデータ登録が完了しました。」と成功メッセージも表示されていますね!

20250131_django-import-database-from-csv-05

Django管理画面にも、問題なくデータが反映されています!

20250131_django-import-database-from-csv-06

もしアップロードされたファイルがCSVでない場合は、エラーメッセージも表示されます。

最後に

CSVを利用してDjangoのデータベースにデータをインポートする方法を解説しました。
CSV形式でデータを作成して、サクッとインポートできるようにしておけばデータの扱いが楽ですよね!
テストデータを作成したり、マスタデータを作成したい時に是非試してみてくださいね!


\ よかったらシェアしてね /

関連記事