ブログBLOG

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

【Django】データベースからCSV形式でデータをエクスポートしてダウンロードする方法

Django
csv , django , python
20250112_django-database-export-csv-download-tmb

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

Djangoを使用してデータベースからデータをエクスポートし、CSV形式でダウンロードしたい時ってありませんか?
分析や他の用途で活用する時など。
そんな時にDjangoを使用してデータベースのデータをCSV形式でエクスポートし、ダウンロードする方法をご紹介します!


CSVダウンロード画像
上記のように、「CSVダウンロード」ボタンからデータを簡単にCSV形式でダウンロードできる機能を実装します。

目次

実行環境

Docker Desktop:4.37.1
Python:3.12.8
Django:5.1.3

フォルダ構成

sample_web/
├── .env                    # 環境変数ファイル
├── 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/         # マイグレーションファイル

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

モデル定義を作成

まず初めに、例として使用する従業員モデルを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を行います。

20250112_django-database-export-csv-download-02

migrate完了後、従業員データを10件登録しました。
次にCSVダウンロード機能を実装します。

CSVダウンロード機能をビューに作成

CSVダウンロード機能をhome/views.pyに作成します。

views.py
import csv
from django.views.generic import TemplateView
from django.http import HttpResponse
from .models import Employee

# ダウンロードページ
class SamplePage(TemplateView):

    template_name = "sample.html"
    model = Employee

    # Employeeモデルの全データを取得して表示
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)

        ctx["employees"] = self.model.objects.all()
        return ctx

    # CSVダウンロード処理
    def post(self, request, *args, **kwargs):

        # ファイル名を設定
        filename = f"employee_list.csv"

        # 文字コード
        charset = "cp932"

        # レスポンスをCSV形式に設定
        response = HttpResponse(content_type=f"text/csv; charset={charset}")
        response["Content-Disposition"] = f'attachment; filename="{filename}"'

        # CSVライターを初期化
        writer = csv.writer(response)

        # ヘッダー行を追加
        writer.writerow(["ID", "氏名", "所属名", "年齢", "作成日時"])

        # フィールド名に基づいてデータを取得
        result = self.model.objects.values(
            "id",
            "employee_name",
            "organization_name",
            "age",
            "created_at",
        )

        # データ行を追加
        for row in result:
            writer.writerow(
                [
                    row["id"],
                    row["employee_name"],
                    row["organization_name"],
                    row["age"],
                    row["created_at"],
                ]
            )

        return response

CSVダウンロード機能全体のプログラムです。
詳しく解説しますね。

views.py
import csv
from django.views.generic import TemplateView
from django.http import HttpResponse
from .models import Employee

必要なライブラリをインポートしています。
modelsは、ご自身が用意したモデルをインポートしてください。

views.py
# Employeeモデルの全データを取得して表示(なくてもOK)
def get_context_data(self, **kwargs):
    ctx = super().get_context_data(**kwargs)

    ctx["employees"] = self.model.objects.all()
    return ctx

従業員全データを画面に表示するコードです。
※ データの確認に使用するため、CSVダウンロード機能には関係なく、なくても問題ありません。

views.py
# CSVダウンロード処理
def post(self, request, *args, **kwargs):

    # ファイル名を設定
    filename = f"employee_list.csv"

    # 文字コード
    charset = "cp932"

    # レスポンスをCSV形式に設定
    response = HttpResponse(content_type=f"text/csv; charset={charset}")
    response["Content-Disposition"] = f'attachment; filename="{filename}"'

    # CSVライターを初期化
    writer = csv.writer(response)

    # ヘッダー行を追加
    writer.writerow(["ID", "氏名", "所属名", "年齢", "作成日時"])

    # フィールド名に基づいてデータを取得
    result = self.model.objects.values(
        "id",
        "employee_name",
        "organization_name",
        "age",
        "created_at",
    )

    # データ行を追加
    for row in result:
        writer.writerow(
            [
                row["id"],
                row["employee_name"],
                row["organization_name"],
                row["age"],
                row["created_at"],
            ]
        )

    return response

データベースから従業員全データをCSV形式でダウンロードするコードです。

views.py
# ファイル名を設定(好きな名前でOK)
filename = f"employee_list.csv"

# 文字コード
charset = "cp932"

ファイル名と文字コードを指定します。

ファイル名は、好きな名前で大丈夫です。
今回は、従業員データなのでemployee_list.csvにしました。

文字コードは、エクセルで開いて確認するため、cp932にしました。
utf-8にする場合は、「charset = "utf-8"」に変更してください。

views.py
# ヘッダー行を追加
writer.writerow(["ID", "氏名", "所属名", "年齢", "作成日時"])

出力する列名を指定します。
今回は、従業員モデルの全てのフィールドを出力します。
ご自身で好きな列名を指定してください。
※ モデルのフィールド表示名と同じにする必要はありません。

views.py
# フィールド名に基づいてデータを取得
result = self.model.objects.values(
    "id",
    "employee_name",
    "organization_name",
    "age",
    "created_at",
)

# データ行を追加
for row in result:
    writer.writerow(
        [
            row["id"],
            row["employee_name"],
            row["organization_name"],
            row["age"],
            row["created_at"],
        ]
    )

従業員全データを取得して、CSVにデータを書き込む処理になります。
ご自身で出力するモデルのフィールド名を指定してください。
今回は、従業員モデルで作成したフィールド名を指定しています。

外部キーのフィールド名を指定したい場合

views.py
organization = models.ForeignKey(
    OrganizationType, verbose_name=_("所属区分"), on_delete=models.PROTECT
)

# 外部キー名__フィールド名で指定可能
result = self.model.objects.values(
    "organization__organization_name",
)

もし、上記のように外部キーにあるフィールド名を指定したい場合は、アンダーバーを2個「__」繋げることで指定できます。

urls.pyを作成

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

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

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

以上で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>サンプルページ</title>
  </head>
  <body>
    <main>
      <h1>従業員一覧</h1>
      <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>
      <form action="" method="POST">
        {% csrf_token %}
        <button type="submit">CSVダウンロード</button>
      </form>
    </main>
  </body>
</html>

CSVをダウンロードする画面全体のプログラムです。
詳しく解説しますね。

sample.html
<h1>従業員一覧</h1>
<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>

従業員全データを表示します。
※ CSVのダウンロードには、なくても問題ありません。

sample.html
<form action="" method="POST">
    {% csrf_token %}
    <button type="submit">CSVダウンロード</button>
</form>

CSVをダウンロードするボタンです。
CSVダウンロードボタンを設置してPOSTで送ります。

これでCSVをダウンロードする画面が完成しました!
実際に動作を確認します。

CSVダウンロードの動作確認

20250112_django-database-export-csv-download-03

現在登録済の従業員全データをテーブル表示しています。
その下に「CSVダウンロード」ボタンを設置しました。
「CSVダウンロード」ボタンをクリックすると指定したファイル名でCSVがダウンロードできます。

20250112_django-database-export-csv-download-04

中身も問題なく従業員全データが書き出されていますね!
バッチグー!

絞り込み機能の実装

全てのデータをCSV形式で書き出すことはできましたが、特定の条件でデータを絞り込み、絞り込んだデータをCSVに出力したい時もありますよね。
ここからは、データを絞り込み、条件に合った内容をCSVに出力する方法も解説します。

絞り込みフォームの作成

絞り込みを行うフォームをhome/forms.pyに作成します。
forms.pyファイルがない場合は、ご自身で新規作成をしてください。

home/forms.py
from django import forms

# 絞り込みフォーム
class DownloadForm(forms.Form):

    age = forms.IntegerField(
        label="年齢",
        min_value=0,
        max_value=120,
        widget=forms.NumberInput(attrs={"placeholder": "年齢を入力してください"}),
    )

絞り込みを行うフォーム「DownloadForm」を作成しました。
今回は、年齢が30歳以下の従業員を絞り込む処理を実装してみます。

絞り込み処理の作成

絞り込んだデータをCSVとしてダウンロードできるように、home/views.pyを変更します。

home/views.py
import csv
from django.views.generic import FormView
from django.http import HttpResponse
from .models import Employee
from .forms import DownloadForm

# ダウンロードページ(絞り込みバージョン)
class SamplePage(FormView):

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

    # Employeeモデルの全データを取得して表示
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)

        ctx["employees"] = self.model.objects.all()
        return ctx

    # CSVダウンロード処理
    def form_valid(self, form):

        # 絞り込み年齢を取得
        age = form.cleaned_data.get("age")

        # ファイル名を設定
        filename = f"employee_list.csv"

        # 文字コード
        charset = "cp932"

        # レスポンスをCSV形式に設定
        response = HttpResponse(content_type=f"text/csv; charset={charset}")
        response["Content-Disposition"] = f'attachment; filename="{filename}"'

        # CSVライターを初期化
        writer = csv.writer(response)

        # ヘッダー行を追加
        writer.writerow(["ID", "氏名", "所属名", "年齢", "作成日時"])

        # フィールド名に基づいてデータを取得
        result = self.model.objects.filter(age__lte=age).values(
            "id",
            "employee_name",
            "organization_name",
            "age",
            "created_at",
        )

        # データ行を追加
        for row in result:
            writer.writerow(
                [
                    row["id"],
                    row["employee_name"],
                    row["organization_name"],
                    row["age"],
                    row["created_at"],
                ]
            )

        return response

全体のプログラムです。
変更点を詳しく解説しますね。

home/views.py
import csv
from django.views.generic import FormView # <- FormViewに変更
from .forms import DownloadForm

新たに3つを追加インポートします。
ビューは、先ほど使用した「TemplateView」から「FormView」に変更します。

home/views.py
form_class = DownloadForm

フォームクラスに絞り込みフォームを指定します。

home/views.py
# CSVダウンロード処理
def form_valid(self, form):

    # 絞り込み年齢を取得
    age = form.cleaned_data.get("age")

post関数からform_valid関数に変更します。
絞り込み年齢をフォームから取得するコードを追加します。

home/views.py
# フィールド名に基づいてデータを取得(年齢で絞り込む)
result = self.model.objects.filter(age__lte=age).values(
    "id",
    "employee_name",
    "organization_name",
    "age",
    "created_at",
)

絞り込みフィルター「filter(age__lte=age)」を追加します。
ご自身で絞り込みたいフィールドを指定してください。
今回は、従業員全データから指定した年齢以下を絞り込んで取得する処理になります。

除外して取得する場合

home/views.py
# 指定した年齢以外の従業員データを取得
result = self.model.objects.exclude(age=age).values(
    "id",
    "employee_name",
    "organization_name",
    "age",
    "created_at",
)

除外して取得する場合は、「exclude(age=age)」にすることで、指定したデータ以外を全て取得できます。
この例では、従業員全データから指定した年齢以外を取得する処理になります。

絞り込みフォームの表示

絞り込みフォームをtemplates/sample.htmlに追加します。

sample.html

<form action="" method="POST">
    {% csrf_token %}
    {{ form.age }} <!-- 絞り込みフォーム追加 -->
    <button type="submit">CSVダウンロード</button>
</form>

先ほど作成したformタグの中に絞り込みフォームを追加します。
今回は、年齢で絞り込む入力フォームを追加しました。
これでデータを絞り込んでCSVをダウンロードできます。
動作確認してみましょう。

CSVダウンロードの動作確認(絞り込みあり)

20250112_django-database-export-csv-download-05

絞り込みたい年齢を入力し、「CSVダウンロード」ボタンをクリックします。

20250112_django-database-export-csv-download-06

すると、30歳以下の従業員データのみが書き出されます!

20250112_django-database-export-csv-download-07

また、30歳以外の従業員も問題なく書き出すことができました!
これで簡単に絞り込んだデータをCSVとしてダウンロードできます。

最後に

Djangoを使用してデータベースからCSV形式でデータをエクスポートしてダウンロードする方法を解説しました。
CSV形式でデータを出力して分析を行ったり、別の用途に使用する場面が多々ありますよね!
そんな時に是非試してみてくださいね!


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

関連記事