こんにちは、DXCEL WAVEの運営者(@dxcelwave)です!
CRUDとは
CRUDとはデータベースを利用するための基本機能を指し、頭文字をとって以下4つに分けられます。
Create | テーブル上にレコードを新規作成 |
---|---|
Read | テーブルからレコードを参照 |
Update | テーブルにある既存レコードの内容更新 |
Delete | テーブルにある既存レコードを削除 |
上記4機能が実装できると、Webアプリ上からデータベースにアクセスし、自由にレコードが操作できるようになります。
CRUD操作を実現するクラスベースビュー(Create・Update・Delete View)
CRUD機能をWebアプリ上に実装する場合、上図Model、View、Templateをそれぞれ編集します。Modelにはデータベースに登録するテーブル情報を記述し、Viewにはテーブルのレコード操作に関する内容を記述します。最後に、Templateはクライアント側に表示する画面デザインを記述します。
ここでViewに記述するCRUD操作は、関数形式で記述していくとコードが複雑になりがちです。それを解消するためにDjangoにはCRUD操作をシンプルに実現するためのクラスベースビューが準備されています。
ビュークラス | 概要 | 利用画面例 |
---|---|---|
ListView | 複数レコードの情報を一覧表示する際に利用 | 一覧画面 |
DetailView | 単一レコードの詳細情報を表示する際に利用 | 詳細画面 |
CreateView | 新たにレコード生成する際に利用 | 新規登録画面 |
UpdateView | 既存レコードの中身を更新する際に利用 | 編集画面 |
DeleteView | 既存レコード削除する際に利用 | 削除画面 |
本記事では上記のクラスベースビューを活用したCRUD機能を持つWebアプリの実装方法を解説します。ここで、クラスベースビューの基本概要を知りたい方はこちらの記事もご覧ください。
【Django】クラスベースビュー基本操作入門|PythonによるWebアプリ開発#12
クラスベースビュー(Class Based View)の概要説明した記事です。 「そもそもクラスベースビューとは何か?」「ビュークラスとビュー関数の記述方法の違いは?」「代表的なクラスベースビューではどんなことができる?」このような疑問にお応えします。
Webアプリ実装イメージ
Webアプリ構築前に、アプリ実装後のイメージを掴みましょう。本記事では上図のようなサイトマップからなるWebアプリを実装します。
またWebアプリのデータベース内に実装するテーブルは上記を想定します。続いて個々の画面イメージを見ていきましょう。
一覧画面イメージ
トップページは会社一覧と題して上図のような画面を作成します。ポイントはListViewのクラスと連携し、Companyテーブルのレコードを一覧表示する点です。
詳細画面イメージ
詳細ページでは、上図のようにCompanyテーブル1レコードに紐づく従業員情報を表示します。ポイントは、DetailViewのクラスと連携し、画面実装する点です。
登録・更新画面イメージ
会社登録および更新画面は上記のようにフォーム形式で実装します。ここでは、CreateViewとUpdateViewと連携するのが特徴です。
削除画面イメージ
最後に削除画面ページは上図イメージで実装します。ポイントはDeleteViewのクラスで実装することであり、上図「削除ボタン」を押すと対象のレコードが削除されるような仕様にします。
【実践】CRUD機能を実装したWebアプリの作成
お待たせしました!それでは実際にプログラミングしていきます。
ディレクトリ構成
ディレクトリ構成は上図に準拠しWebアプリを構築します。各ファイルの利用目的は下記です。
ファイル名 | 用途 |
---|---|
models.py | DB連携・テーブル作成。 |
urls.py | 画面表示設定。 |
views.py | 画面表示設定。 |
Company_list.html | 会社一覧画面のデザイン。ListViewと連携。 |
Company_detail.html | 会社詳細画面のデザイン。DetailViewと連携。 |
Company_form.html | 登録・更新画面のデザイン。CreateViewおよびUpdateViewと連携。 |
Company_delete.html | 削除画面のデザイン。DeleteViewと連携。 |
Header.html | グローバルナビなど共通ヘッダー情報のデザイン。 |
models.py:テーブル作成
CompanyテーブルおよびEmployeeテーブルを作成するために、models.pyにモデルクラスを記述します。
from django.db import models
#会社情報を格納するテーブル
class Company(models.Model):
name = models.CharField(max_length=256)
industory = models.CharField(max_length=256)
location = models.CharField(max_length=256)
def __str__(self):
return self.name
#会社に紐づく従業員情報を格納するテーブル
class Employee(models.Model):
name = models.CharField(max_length=256)
age = models.PositiveIntegerField()
company = models.ForeignKey(Company,related_name='Employees',on_delete=models.CASCADE)
def __str__(self):
return self.name
モデルクラス作成後はマイグレーションを行い、データベースに適用しましょう。マイグレーション方法は下記の記事で紹介しています。適時ご参照ください。
【Django】モデルの操作・データベース作成・削除|PythonによるWebアプリ開発(models.py)#6
Djangoのモデルの構築方法を詳しく紹介します。モデルとは何か?という観点から、モデル構築手順に至るまで知ることができます。また、モデルからデータベースにテーブル登録した後の不具合対応として、データベースの削除方法にも言及します。
urls.py:表示設定
本記事ではurls.pyを下記の仕様で設定します。
- アプリケーションフォルダ内にurls.pyを新規作成
- urls.py(プロジェクト)をurls.py(アプリケーション)にinclude関数で紐付け
- urls.py(アプリケーション)をメインの編集ファイルとして利用
以下実際に記述してみましょう。
プロジェクトフォルダ内のurls.py
from django.contrib import admin
from django.urls import path
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('App_Folder.urls')), #(App_Folder)はご自身で作成したアプリケーションフォルダがあればその名前を記載
]
アプリケーションフォルダ内のurls.py
from django.urls import path
from . import views
app_name = "App"
urlpatterns = [
path('', views.CompanyList.as_view(), name='list'), #一覧画面
path('detail/<int:pk>/',views.CompanyDetail.as_view(),name='detail'), #詳細画面
path('create/',views.CompanyCreateView.as_view(),name='create'), #新規登録画面(会社)
path('create2/',views.CompanyCreateView2.as_view(),name='create2'), #新規登録画面(従業員)
path('update/<int:pk>/',views.CompanyUpdateView.as_view(),name='update'), #更新画面(会社)
path('update2/<int:pk>/',views.CompanyUpdateView2.as_view(),name='update2'),#更新画面(従業員)
path('delete/<int:pk>/',views.CompanyDeleteView.as_view(),name='delete'), #削除画面(会社)
]
URLパターンの設定方法として留意すべきポイントは下記になります。
- 今回クラスベースビューを用いるためクラス名の後に.as_view()を記述すること
- 詳細画面および更新画面は1レコードを参照するため、pathの第一引数はレコードID(PK)と紐付けること
views.py:画面表示
views.pyのコード全量を以下に示します。
from django.shortcuts import render
from django.urls import reverse_lazy
from django.urls import reverse
from django.http import HttpResponse
from django.views.generic import (ListView,
DetailView,
CreateView,
DeleteView,
UpdateView)
from . import models
#一覧画面
class CompanyList(ListView):
#Companyテーブル連携
model = models.Company
#レコード情報をテンプレートに渡すオブジェクト
context_object_name = "company_list"
#テンプレートファイル連携
template_name = "Company_list.html"
#詳細画面
class CompanyDetail(DetailView):
#Companyテーブル連携
model = models.Company
#レコード情報をテンプレートに渡すオブジェクト
context_object_name = "company_detail"
#テンプレートファイル連携
template_name = "Company_detail.html"
#Create(会社)画面
class CompanyCreateView(CreateView):
#Companyテーブル連携
model = models.Company
#入力項目定義
fields = ("name","industory","location")
#テンプレートファイル連携
template_name = "Company_form.html"
#更新後のリダイレクト先
def get_success_url(self):
return reverse('App:detail', kwargs={'pk': self.object.pk})
#Create(従業員)画面
class CompanyCreateView2(CreateView):
#Companyテーブル連携
model = models.Employee
#入力項目定義
fields = ("name","age","company")
#テンプレートファイル連携
template_name = "Company_form.html"
#作成後のリダイレクト先
success_url = reverse_lazy("App:list")
#Upadate画面(会社情報)
class CompanyUpdateView(UpdateView):
#入力項目定義
fields = ("name","industory","location")
#Companyテーブル連携
model = models.Company
#テンプレートファイル連携
template_name = "Company_form.html"
#更新後のリダイレクト先
def get_success_url(self):
return reverse('App:detail', kwargs={'pk': self.object.pk})
#更新画面(従業員情報)
class CompanyUpdateView2(UpdateView):
#入力項目定義
fields = ("name","age")
#Employeeテーブル連携
model = models.Employee
#テンプレートファイル連携
template_name = "Company_form.html"
#更新後のリダイレクト先
success_url = reverse_lazy("App:list")
#削除画面
class CompanyDeleteView(DeleteView):
#Companyテーブル連携
model = models.Company
#テンプレートファイル連携
template_name = "Company_delete.html"
#削除後のリダイレクト先
success_url = reverse_lazy("App:list")
まず一番のポイントは、クラスベースビューを利用している点です。ListView、DetailView、CreateView、DeleteView、UpadateViewクラスを用いるために、下記コードを記述して親クラスを呼び出しています。
from django.views.generic import (ListView,
DetailView,
CreateView,
DeleteView,
UpdateView)
続いて、各クラスベースビューを見ると、それぞれ似たオブジェクトを活用しているのがわかります。各オブジェクトの役割は下記であり、使いこなせると非常にシンプルなコードで機能実装できるため有用です。
model | モデルクラスを指定すると対象のデータベースのテーブルと連携する |
---|---|
context_object_name | 指定したオブジェクト名をテンプレートに渡す |
template_name | 指定したテンプレートファイルをレンダリングする |
fields | テンプレート側にフォームを設けた際、表示するフィールドを指定 |
success_url | POST処理後のリダイレクト先を指定 |
get_success_url() | POST処理後のリダイレクト先を指定 |
最後に、CreateView、UpdateView、DeleteViewの特徴を紹介します。後に記述するテンプレート上でPOST処理が実行された場合、各クラスビューは下記の役割を遂行します。
ビュークラス | POST処理時の挙動 |
---|---|
CreateView | 新規レコードを作成する |
UpdateView | 既存レコードを更新する |
DeleteView | 既存レコードを削除する |
テンプレートファイル作成
最後にテンプレートファイルを作成します。ファイルは下記5つを作成します。今回CSSのデザインはbootstrap5を用いており、内容は割愛します。
ファイル名 | 用途 |
---|---|
Header.html | グローバルナビなど共通ヘッダー情報をデザイン |
Company_list.html | ListViewと連携し、会社一覧画面をデザイン |
Company_detail.html | DetailViewと連携し、会社詳細画面をデザイン |
Company_form.html | CreateViewおよびUpdateViewと連携し、登録・更新画面をデザイン |
Company_delete.html | DeleteViewと連携し、削除画面をデザイン |
共通ナビ(Header.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<title>CRUD入門</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="navbar-nav">
<!-- urls.pyで定義したアプリ名 + urlpatternのpathで定めたnameを指定し、リンクで遷移できるようにする -->
<a class="navbar-brand" href="{% url 'App:list' %}">CompanyList</a>
</div>
</nav>
<!-- Company_list.htmlのHTMLコンテンツを呼び出し -->
<div class="container">
{% block content_block %}
{% endblock %}
</div>
</body>
</html>
上記は各サイト共通して用いるヘッダー(主にナビメニュー)に該当するテンプレートです。
{% url ‘App:list’ %}というテンプレートタグは、urls.py(アプリケーション)で記述したapp_name=”App”とpathメソッドの引数name=”list”を指定しています。これでリンクから会社一覧画面に遷移できるようになります。
会社一覧画面(Company_list.html)
{% extends "Header.html" %}
{% block content_block %}
<h2>会社一覧</h2>
<table class="table">
<thead>
<tr>
<th>会社名</th>
<th></th>
</tr>
</thead>
<tbody>
{% for company in company_list %}
<tr>
<td>{{ company.name }}</td>
<td><a href="detail/{{ company.id }}">詳細</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="container">
<p><a class='btn btn-primary' href="{% url 'App:create' %}">新規登録</a></p>
<br>
</div>
{% endblock %}
上記は会社一覧画面を表すテンプレートです。views.pyにて記述したcontext_object_name(company_list)をテンプレートに渡すことで、Companyテーブルのレコードを一覧表示します。
詳細画面(Company_Detail.html)
{% extends "Header.html" %}
{% block content_block %}
<div class="jumbotron">
<h2>会社詳細</h2>
<table class="table">
<thead>
<tr>
<th scope="col">会社</th>
<th scope="col">業界</th>
<th scope="col">地域</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ company_detail.name }}</td>
<td>{{ company_detail.industory }}</td>
<td>{{ company_detail.location }}</td>
</tr>
<tbody>
</table>
<div class="container">
<p><a class='btn btn-primary' href="{% url 'App:update' pk=company_detail.pk %}">更新</a></p>
<br>
</div>
<h2>従業員</h2>
<table class="table">
<thead>
<tr>
<th scope="col">名前</th>
<th scope="col">年齢</th>
<th scope="col">詳細</th>
</tr>
</thead>
<tbody>
{% for employee in company_detail.Employees.all %}
<tr>
<td>{{ employee.name }}</td>
<td>{{ employee.age }}</td>
<td><a href="{% url 'App:update2' pk=employee.pk %}">詳細</a></td>
</tr>
{% endfor %}
<tbody>
</table>
<div class="container">
<p><a class='btn btn-primary' href="{% url 'App:create2' %}">新規登録</a></p>
<br>
</div>
<div><a href="{% url 'App:delete' pk=company_detail.pk %}">>>>会社情報を削除する</a></div>
</div>
{% endblock %}
上記は会社詳細画面を表すテンプレートです。記述方法は会社一覧画面と同様にオブジェクトを指定してテーブルレコードを一覧表示しています。
新規登録・更新画面(Company_form.html)
{% extends "Header.html" %}
{% block content_block %}
<h1>
{% if not form.instance.pk %}
会社を登録する
{% else %}
会社・従業員情報を更新する
{% endif %}
</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class='btn btn-primary' value="登録">
</form>
{% endblock %}
上記は新規登録画面および更新画面を表すテンプレートです。新規登録画面と更新画面は同一のテンプレートで実装しています。Webアプリを利用するユーザーにとって新規登録画面か更新画面か見分けられるように、下記で対応しているのがポイントです。
{% if not form.instance.pk %}
会社を登録する
{% else %}
会社・従業員情報を更新する
{% endif %}
削除画面(Company_delete.html)
{% extends "Header.html" %}
{% block content_block %}
<h1>本当に削除しますか?</h1>
<form method="post">
{% csrf_token %}
<input type="submit" class="btn btn-danger" value="削除">
<a href="{% url 'App:detail' pk=company.pk %} ">キャンセル</a>
</form>
{% endblock %}
最後に削除画面を表すテンプレートを示します。
これでWebアプリは完成です!最後にローカルサーバーを開き、画面が表示できるか確認してみましょう。
【参考】Djangoの解説記事一覧
最後までご覧いただきありがとうございました。当サイトではDjangoフレームワークを用いた解説記事を多数取り扱っております。次のように体系的に整理しておりますため学習にお役立て下さい。
Django学習に最適!
当サイトが運営するDjango記事一覧
【参考】Pythonでできること・お仕事探し
最後に
お問い合わせフォーム
上記課題に向けてご気軽にご相談下さい。
お問い合わせはこちら