ご覧いただきありがとうございます!
領護(りょうご)です。
Djangoを使用してデータベースからデータをエクスポートし、CSV形式でダウンロードしたい時ってありませんか?
分析や他の用途で活用する時など。
そんな時にDjangoを使用してデータベースのデータを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ダウンロード機能をビューに作成までスキップしてください。、
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に作成します。
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を行います。
migrate完了後、従業員データを10件登録しました。
次にCSVダウンロード機能を実装します。
CSVダウンロード機能をビューに作成
CSVダウンロード機能をhome/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ダウンロード機能全体のプログラムです。
詳しく解説しますね。
import csv
from django.views.generic import TemplateView
from django.http import HttpResponse
from .models import Employee
必要なライブラリをインポートしています。
modelsは、ご自身が用意したモデルをインポートしてください。
# Employeeモデルの全データを取得して表示(なくてもOK)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx["employees"] = self.model.objects.all()
return ctx
従業員全データを画面に表示するコードです。
※ データの確認に使用するため、CSVダウンロード機能には関係なく、なくても問題ありません。
# 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形式でダウンロードするコードです。
# ファイル名を設定(好きな名前でOK)
filename = f"employee_list.csv"
# 文字コード
charset = "cp932"
ファイル名と文字コードを指定します。
ファイル名は、好きな名前で大丈夫です。
今回は、従業員データなのでemployee_list.csvにしました。
文字コードは、エクセルで開いて確認するため、cp932にしました。
utf-8にする場合は、「charset = "utf-8"」に変更してください。
# ヘッダー行を追加
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"],
]
)
従業員全データを取得して、CSVにデータを書き込む処理になります。
ご自身で出力するモデルのフィールド名を指定してください。
今回は、従業員モデルで作成したフィールド名を指定しています。
外部キーのフィールド名を指定したい場合
organization = models.ForeignKey(
OrganizationType, verbose_name=_("所属区分"), on_delete=models.PROTECT
)
# 外部キー名__フィールド名で指定可能
result = self.model.objects.values(
"organization__organization_name",
)
もし、上記のように外部キーにあるフィールド名を指定したい場合は、アンダーバーを2個「__」繋げることで指定できます。
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に作成します。
{% 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をダウンロードする画面全体のプログラムです。
詳しく解説しますね。
<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のダウンロードには、なくても問題ありません。
<form action="" method="POST">
{% csrf_token %}
<button type="submit">CSVダウンロード</button>
</form>
CSVをダウンロードするボタンです。
CSVダウンロードボタンを設置してPOSTで送ります。
これでCSVをダウンロードする画面が完成しました!
実際に動作を確認します。
CSVダウンロードの動作確認
現在登録済の従業員全データをテーブル表示しています。
その下に「CSVダウンロード」ボタンを設置しました。
「CSVダウンロード」ボタンをクリックすると指定したファイル名でCSVがダウンロードできます。
中身も問題なく従業員全データが書き出されていますね!
バッチグー!
絞り込み機能の実装
全てのデータをCSV形式で書き出すことはできましたが、特定の条件でデータを絞り込み、絞り込んだデータをCSVに出力したい時もありますよね。
ここからは、データを絞り込み、条件に合った内容をCSVに出力する方法も解説します。
絞り込みフォームの作成
絞り込みを行うフォームをhome/forms.pyに作成します。
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を変更します。
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
全体のプログラムです。
変更点を詳しく解説しますね。
import csv
from django.views.generic import FormView # <- FormViewに変更
from .forms import DownloadForm
新たに3つを追加インポートします。
ビューは、先ほど使用した「TemplateView」から「FormView」に変更します。
form_class = DownloadForm
フォームクラスに絞り込みフォームを指定します。
# CSVダウンロード処理
def form_valid(self, form):
# 絞り込み年齢を取得
age = form.cleaned_data.get("age")
post関数からform_valid関数に変更します。
絞り込み年齢をフォームから取得するコードを追加します。
# フィールド名に基づいてデータを取得(年齢で絞り込む)
result = self.model.objects.filter(age__lte=age).values(
"id",
"employee_name",
"organization_name",
"age",
"created_at",
)
絞り込みフィルター「filter(age__lte=age)」を追加します。
ご自身で絞り込みたいフィールドを指定してください。
今回は、従業員全データから指定した年齢以下を絞り込んで取得する処理になります。
除外して取得する場合
# 指定した年齢以外の従業員データを取得
result = self.model.objects.exclude(age=age).values(
"id",
"employee_name",
"organization_name",
"age",
"created_at",
)
除外して取得する場合は、「exclude(age=age)」にすることで、指定したデータ以外を全て取得できます。
この例では、従業員全データから指定した年齢以外を取得する処理になります。
絞り込みフォームの表示
絞り込みフォームをtemplates/sample.htmlに追加します。
<form action="" method="POST">
{% csrf_token %}
{{ form.age }} <!-- 絞り込みフォーム追加 -->
<button type="submit">CSVダウンロード</button>
</form>
先ほど作成したformタグの中に絞り込みフォームを追加します。
今回は、年齢で絞り込む入力フォームを追加しました。
これでデータを絞り込んでCSVをダウンロードできます。
動作確認してみましょう。
CSVダウンロードの動作確認(絞り込みあり)
絞り込みたい年齢を入力し、「CSVダウンロード」ボタンをクリックします。
すると、30歳以下の従業員データのみが書き出されます!
また、30歳以外の従業員も問題なく書き出すことができました!
これで簡単に絞り込んだデータをCSVとしてダウンロードできます。
最後に
Djangoを使用してデータベースからCSV形式でデータをエクスポートしてダウンロードする方法を解説しました。
CSV形式でデータを出力して分析を行ったり、別の用途に使用する場面が多々ありますよね!
そんな時に是非試してみてくださいね!