
このドキュメントでは、Django の Class Based View について、 CRUD の実装方法について具体的に説明します。Djangoは、Webアプリケーションの開発に使用されるPythonのフレームワークの1つであり、Class Based Viewを使用することで、効率的にWebアプリケーションを開発することができます。
Contents
class based view での CRUD とは
CRUDとは、Create(作成)、Read(読み取り)、Update(更新)、Delete(削除)の頭文字を取ったもので、Webアプリケーションにおいて、データの作成、読み取り、更新、削除の機能を提供することを指します。
class based view で CRUDの実装方法
以下の手順に従って、CRUDを実装することができます。
models.pyにモデルを定義する。forms.pyにフォームを定義する。views.pyにCreate View、Retrieve View、Update View、Delete Viewを定義する。urls.pyにURLを設定する。
1. models.pyにモデルを定義する
まずは、CRUDで使用するモデルを定義します。モデルは、データベースのテーブルに対応するPythonのクラスです。例えば、以下のようなmodels.pyファイルを作成します。
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
published_date = models.DateField()
この例では、Bookというモデルを定義しています。Bookモデルは、書籍のタイトル、著者、出版日を表す3つのフィールドを持っています。
2. forms.pyにフォームを定義する
次に、CRUDで使用するフォームを定義します。フォームは、WebページのHTMLフォームと対応するPythonのクラスであり、ユーザーが入力したデータを受け取り、バリデーションを行います。例えば、以下のようなforms.pyファイルを作成します。
from django import forms
from .models import Book
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = ['title', 'author', 'published_date']この例では、BookFormというフォームを定義しています。BookFormは、Bookモデルと対応するフォームであり、title、author、published_dateの3つのフィールドを持ちます。
3. views.pyにCreate View、Retrieve View、Update View、Delete Viewを定義する
次に、Create View、Retrieve View、Update View、Delete Viewを定義します。それぞれのViewには、CreateView、DetailView、UpdateView、DeleteViewというクラスを継承し、model、form_class、success_urlなどの属性を指定します。
Create View
Create Viewは、データの作成を行うためのViewです。例えば、以下のようなviews.pyファイルを作成します。
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .models import Book
from .forms import BookForm
class BookCreateView(CreateView):
model = Book
form_class = BookForm
success_url = reverse_lazy('book_list')
この例では、BookCreateViewというCreate Viewを定義しています。BookCreateViewでは、BookモデルとBookFormフォームを使用し、データの保存が成功した場合にbook_listというURLに遷移します。
Retrieve View
Retrieve Viewは、データの読み取りを行うためのViewです。例えば、以下のようなviews.pyファイルを作成します。
from django.views.generic.detail import DetailView
from .models import Book
class BookDetailView(DetailView):
model = Book
この例では、BookDetailViewというRetrieve Viewを定義しています。BookDetailViewでは、Bookモデルを使用し、book_detail.htmlというテンプレートを表示します。
Update View
Update Viewは、データの更新を行うためのViewです。例えば、以下のようなviews.pyファイルを作成します。
from django.views.generic.edit import UpdateView
from django.urls import reverse_lazy
from .models import Book
from .forms import BookForm
class BookUpdateView(UpdateView):
model = Book
form_class = BookForm
success_url = reverse_lazy('book_list')この例では、BookUpdateViewというUpdate Viewを定義しています。BookUpdateViewでは、BookモデルとBookFormフォームを使用し、データの保存が成功した場合にbook_listというURLに遷移します。
Delete View
Delete Viewは、データの削除を行うためのViewです。例えば、以下のようなviews.pyファイルを作成します。
from django.views.generic.edit import DeleteView
from django.urls import reverse_lazy
from .models import Book
class BookDeleteView(DeleteView):
model = Book
success_url = reverse_lazy('book_list')
この例では、BookDeleteViewというDelete Viewを定義しています。BookDeleteViewでは、Bookモデルを使用し、データの削除が成功した場合にbook_listというURLに遷移します。
4. urls.pyにURLを設定する
最後に、urls.pyで、各Viewに対応するURLを設定します。例えば、以下のようなurls.pyファイルを作成します。
from django.urls import path
from .views import BookListView, BookCreateView, BookDetailView, BookUpdateView, BookDeleteView
urlpatterns = [
path('', BookListView.as_view(), name='book_list'),
path('create/', BookCreateView.as_view(), name='book_create'),
path('<int:pk>/', BookDetailView.as_view(), name='book_detail'),
path('<int:pk>/update/', BookUpdateView.as_view(), name='book_update'),
path('<int:pk>/delete/', BookDeleteView.as_view(), name='book_delete'),
]
この例では、urlpatternsに、BookListView、BookCreateView、BookDetailView、BookUpdateView、BookDeleteViewに対応するURLを設定しています。
これで、CRUDの実装が完了しました。
テンプレートの作成
テンプレートのディレクトリ階層については、Djangoの公式ドキュメントにおいても特に明確に定められていません。しかし、一般的には以下のようなディレクトリ階層を採用することが多いです。
myproject/
myproject/
settings.py
urls.py
...
myapp/
templates/
myapp/
base.html
book_list.html
book_detail.html
book_form.html
...
views.py
models.py
...
...
このように、アプリケーションごとにtemplatesディレクトリを作成し、その中にテンプレートを格納することが一般的です。さらに、templatesディレクトリ内に、各アプリケーションごとにサブディレクトリを作成し、その中にテンプレートを格納することが推奨されています。これにより、複数のアプリケーションを持つプロジェクトでも、テンプレートの管理が容易になります。
また、base.htmlなど、共通で使用するテンプレートは、アプリケーションごとに1つのファイルにまとめることが多いです。これにより、重複するコードを減らし、テンプレートの保守性を高めることができます。
テンプレートの継承
Djangoアプリケーションでは、各Viewで表示するHTMLのテンプレートを作成する必要があります。テンプレートは、Webページの構成要素を定義し、Viewが生成したデータを表示するためのものです。
Djangoにおけるテンプレートは、HTMLを拡張したものであり、テンプレートエンジンによって処理されます。テンプレートエンジンは、テンプレート内のタグや変数を解釈して、HTMLに変換します。Djangoには、デフォルトでdjango.template.backends.django.DjangoTemplatesというテンプレートエンジンが用意されており、柔軟なテンプレート処理を実現しています。
テンプレートを作成するには、まずテンプレートを継承するベーステンプレートを定義します。これにより、各Viewで表示するHTMLの共通部分をまとめることができます。例えば、以下のようなbase.htmlテンプレートを作成します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
テンプレートの定義
次に、各Viewで表示するHTMLのテンプレートを定義します。例えば、以下のようなbook_list.htmlテンプレートを作成します。
{% extends 'base.html' %}
{% block title %}書籍一覧{% endblock %}
{% block content %}
<h1>書籍一覧</h1>
<ul>
{% for book in object_list %}
<li><a href="{% url 'book_detail' book.pk %}">{{ book.title }}</a></li>
{% empty %}
<li>No books yet.</li>
{% endfor %}
</ul>
<a href="{% url 'book_create' %}">新規作成</a>
{% endblock %}
この例では、{% extends 'base.html' %}によって、base.htmlを継承しています。{% block title %}と{% endblock %}で囲まれた部分は、ページのタイトルを定義するための部分になります。{% block content %}と{% endblock %}で囲まれた部分が、各Viewで表示するコンテンツになります。{% for %}と{% endfor %}で囲まれた部分は、BookListViewで表示する書籍一覧の部分になります。{% empty %}は、書籍が存在しない場合に表示される文言です。{% url %}は、URLを動的に生成するためのテンプレートタグです。
BookDetailViewで表示するテンプレートも同様に定義します。例えば、以下のようなbook_detail.htmlテンプレートを作成します。
{% extends 'base.html' %}
{% block title %}{{ object.title }}{% endblock %}
{% block content %}
<h1>{{ object.title }}</h1>
<p><strong>著者:</strong> {{ object.author }}</p>
<p><strong>出版日:</strong> {{ object.published_date }}</p>
<a href="{% url 'book_update' object.pk %}">編集</a>
<form action="{% url 'book_delete' object.pk %}" method="post">
{% csrf_token %}
<input type="submit" value="削除">
</form>
{% endblock %}
この例では、{% extends 'base.html' %}によって、base.htmlを継承しています。{% block title %}と{% endblock %}で囲まれた部分は、ページのタイトルを定義するための部分になります。{% block content %}と{% endblock %}で囲まれた部分が、各Viewで表示するコンテンツになります。{{ object }}は、BookDetailViewで指定したmodelのインスタンスになります。{% url 'book_update' object.pk %}は、BookUpdateViewに対応するURLを動的に生成するためのテンプレートタグです。<form>タグは、書籍の削除を行うためのフォームです。{% csrf_token %}は、セキュリティ対策のために必要なテンプレートタグです。
BookCreateViewとBookUpdateViewで表示するテンプレートも同様に定義します。例えば、以下のようなbook_form.htmlテンプレートを作成します。
{% extends 'base.html' %}
{% block title %}{{ form_title }}{% endblock %}
{% block content %}
<h1>{{ form_title }}</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="保存">
</form>
{% endblock %}
この例では、{% extends 'base.html' %}によって、base.htmlを継承しています。{% block title %}と{% endblock %}で囲まれた部分は、ページのタイトルを定義するための部分になります。{% block content %}と{% endblock %}で囲まれた部分が、各Viewで表示するコンテンツになります。{{ form_title }}は、フォームのタイトルを表します。{{ form.as_p }}は、フォームのフィールドを<p>タグで囲んで表示するためのテンプレートタグです。<form>タグは、フォームの送信を行うためのものです。
BookDeleteViewでは、テンプレートを定義する必要はありません。
フォームのバリデーション
Djangoのフォームは、クライアントサイドとサーバーサイドの両方でバリデーションを行うことができます。クライアントサイドのバリデーションは、JavaScriptを用いてブラウザ上で行われます。一方、サーバーサイドのバリデーションは、View内で行われます。
フォームのバリデーションは、forms.py内で行います。例えば、以下のようなBookFormを定義します。
from django import forms
from .models import Book
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = ('title', 'author', 'published_date')
def clean_title(self):
title = self.cleaned_data['title']
if len(title) < 3:
raise forms.ValidationError('タイトルは3文字以上で入力してください。')
return title
この例では、BookFormというフォームを定義しています。Metaクラスには、フォームで使用するモデルとフィールドを指定します。clean_titleメソッドは、titleフィールドのバリデーションを行うためのメソッドです。self.cleaned_dataには、フォームから送信されたデータが含まれています。len(title)でタイトルの文字数を取得し、3文字未満の場合は、forms.ValidationErrorでエラーを発生させます。
Viewでは、以下のようにバリデーションを行います。
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Book
from .forms import BookForm
class BookCreateView(CreateView):
model = Book
form_class = BookForm
template_name = 'book_form.html'
success_url = reverse_lazy('book_list')
class BookUpdateView(UpdateView):
model = Book
form_class = BookForm
template_name = 'book_form.html'
success_url = reverse_lazy('book_list')
class BookDeleteView(DeleteView):
model = Book
success_url = reverse_lazy('book_list')
この例では、BookCreateViewとBookUpdateViewで使用するフォームとして、BookFormを指定しています。フォームのバリデーションは、BookFormのclean_titleメソッドで実行されます。バリデーションに失敗した場合は、エラーメッセージが表示されます。
フォームのバリデーションは、データの正当性を確認するために非常に重要な処理です。クライアントサイドのバリデーションだけでなく、サーバーサイドのバリデーションも行うことで、より信頼性の高いWebアプリケーションを開発することができます。
class based view のクラスのカスタマイズ
DjangoのClass-Based View(以下、CBV)の中でも、よく使われるビューには以下の4つがあります。
- CreateView
- UpdateView
- DeleteView
- DetailView
それぞれのビューについて、カスタマイズ方法を説明します。
CreateViewのカスタマイズ
CreateViewは、モデルに新しいレコードを追加するためのビューです。フォームを提供し、フォームの入力値をモデルの新しいレコードとして保存します。
CreateViewをカスタマイズするには、以下の手順を踏みます。
CreateViewを継承する- ビューで利用するフォームクラスを指定する
- フォームの入力値を保存するためのメソッドをオーバーライドする
例えば、以下のようにします。
from django.views.generic.edit import CreateView
from .models import Book
from .forms import BookForm
class BookCreateView(CreateView):
model = Book
form_class = BookForm
template_name = 'book_create.html'
def form_valid(self, form):
# フォームの入力値を保存する処理を実装する
return super().form_valid(form)
この例では、BookCreateViewというクラスを定義しています。CreateViewを継承しているため、model属性にBookモデルを、form_class属性にはフォームクラスを指定することで、フォームを提供し、フォームの入力値をBookモデルの新しいレコードとして保存するViewとして利用することができます。template_name属性には、テンプレートファイルのパスを指定します。
form_validメソッドをオーバーライドすることで、フォームの入力値を保存するための処理をカスタマイズすることができます。例えば、以下のように書くことで、フォームの入力値を保存する前に、ユーザー名をログに出力することができます。
def form_valid(self, form):
logger.info('User {} created a new book'.format(self.request.user.username))
return super().form_valid(form)
UpdateViewのカスタマイズ
UpdateViewは、モデルの既存のレコードを更新するためのビューです。フォームを提供し、フォームの入力値をモデルの既存のレコードとして保存します。
UpdateViewをカスタマイズするには、以下の手順を踏みます。
UpdateViewを継承する- ビューで利用するフォームクラスを指定する
- フォームの入力値を保存するためのメソッドをオーバーライドする
例えば、以下のようにします。
from django.views.generic.edit import UpdateView
from .models import Book
from .forms import BookForm
class BookUpdateView(UpdateView):
model = Book
form_class = BookForm
template_name = 'book_update.html'
def form_valid(self, form):
# フォームの入力値を保存する処理を実装する
return super().form_valid(form)
この例では、BookUpdateViewというクラスを定義しています。UpdateViewを継承しているため、model属性にBookモデルを、form_class属性にはフォームクラスを指定することで、フォームを提供し、フォームの入力値をBookモデルの既存のレコードとして保存するViewとして利用することができます。template_name属性には、テンプレートファイルのパスを指定します。
form_validメソッドをオーバーライドすることで、フォームの入力値を保存するための処理をカスタマイズすることができます。
DeleteViewのカスタマイズ
DeleteViewは、モデルの既存のレコードを削除するためのビューです。確認画面を提供し、モデルの既存のレコードを削除します。
DeleteViewをカスタマイズするには、以下の手順を踏みます。
DeleteViewを継承する- ビューで利用するモデルを指定する
- モデルの既存のレコードを削除するためのメソッドをオーバーライドする
例えば、以下のようにします。
from django.views.generic.edit import DeleteView
from django.urls import reverse_lazy
from .models import Book
class BookDeleteView(DeleteView):
model = Book
template_name = 'book_delete.html'
success_url = reverse_lazy('book_list')
def delete(self, request, *args, **kwargs):
# モデルの既存のレコードを削除する処理を実装する
return super().delete(request, *args, **kwargs)
この例では、BookDeleteViewというクラスを定義しています。DeleteViewを継承しているため、model属性にBookモデルを指定することで、モデルの既存のレコードを削除するViewとして利用することができます。template_name属性には、テンプレートファイルのパスを指定します。success_url属性には、レコードの削除に成功した場合に遷移するURLを指定します。
deleteメソッドをオーバーライドすることで、モデルの既存のレコードを削除するための処理をカスタマイズすることができます。
DetailViewのカスタマイズ
DetailViewは、モデルの既存のレコードの詳細を表示するためのビューです。
DetailViewをカスタマイズするには、以下の手順を踏みます。
DetailViewを継承する- ビューで利用するモデルを指定する
- テンプレートに渡すコンテキストデータをカスタマイズするためのメソッドをオーバーライドする
例えば、以下のようにします。
from django.views.generic import DetailView
from .models import Book
class BookDetailView(DetailView):
model = Book
template_name = 'book_detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# テンプレートに渡す変数を追加する処理を実装する
return contextこの例では、BookDetailViewというクラスを定義しています。DetailViewを継承しているため、model属性にBookモデルを指定することで、モデルの既存のレコードの詳細を表示するViewとして利用することができます。template_name属性には、テンプレートファイルのパスを指定します。
get_context_dataメソッドをオーバーライドすることで、テンプレートに渡すコンテキストデータをカスタマイズすることができます。例えば、以下のように書くことで、BookDetailViewにbookという変数を追加することができます。
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
book = Book.objects.get(pk=self.kwargs['pk'])
context['book'] = book
return context
Class based viewの利点と欠点まとめ
DjangoのClass-Based View(以下、CBV)は、Djangoアプリケーションの開発において、より抽象化された方法でViewを定義することができる機能です。CBVを使用すると、標準的なViewよりも多くの機能を提供することができます。
CBVの利点には、以下のようなものがあります。
- コードの再利用性が高い
- 共通のコードをまとめることができる
- クラス継承を使用することで、複雑なViewを簡単に実装できる
- 柔軟性が高い
一方、CBVの欠点としては、以下のようなものがあります。
- Viewの機能が増えることで、初心者には理解しにくくなる
- Viewの動作がオーバーライドされることがあるため、デバッグが難しくなることがある
- テンプレートの変数の渡し方が複雑になることがある
CBVは、Django開発の効率化に大きく貢献している機能の一つです。CBVを使用することで、より簡潔で柔軟性の高いアプリケーションを開発することができます。


