こんにちは、かつコーチです。
これまで関数ベースビュー(FBV)でビューを書いてきましたが、Djangoにはもうひとつクラスベースビュー(CBV)という書き方があります。
「FBVで慣れたのに、なぜわざわざクラスで書くの?」と感じる人も多いと思います。
今回はCBVの基本と、FBVとの使い分けを整理していきます。
クラスベースビュー(CBV)とは
FBVとの構造の違い
クラスベースビュー(CBV)とは、ビューを関数ではなくクラスとして定義する書き方です。
まずはFBVとCBVで同じ処理を書いた例を比べてみましょう。
# FBV
def post_list(request):
posts = Post.objects.all()
return render(request, "blog/post_list.html", {"posts": posts})
# CBV
from django.views.generic import ListView
class PostListView(ListView):
model = Post
template_name = "blog/post_list.html"
context_object_name = "posts"
CBVでは、Djangoが用意しているListViewのような汎用ビューを継承し、必要な属性だけを設定する形になります。
一覧表示・詳細表示・作成・更新・削除といった定番の処理は、汎用ビューを使うことで数行にまとめられます。
urls.pyでの呼び出し方
CBVをURLに割り当てるときは、.as_view()を呼び出す点がFBVと異なります。
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path("posts/", views.PostListView.as_view(), name="post_list"),
]
as_view()は、クラスをDjangoが扱える関数の形に変換してくれるメソッドです。
代表的な汎用ビュー
一覧・詳細表示:ListView・DetailView
読み取り系の処理は、この2つで大半をカバーできます。
from django.views.generic import ListView, DetailView
class PostListView(ListView):
model = Post
paginate_by = 10
class PostDetailView(DetailView):
model = Post
DetailViewは、URLから受け取ったpk(主キー)やslugをもとに、自動で該当のレコードを1件取得してくれます。
作成・更新・削除:CreateView・UpdateView・DeleteView
フォームを使った処理も、汎用ビューで簡潔に書けます。
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
class PostCreateView(CreateView):
model = Post
fields = ["title", "content"]
success_url = reverse_lazy("blog:post_list")
success_urlには、処理成功後のリダイレクト先を指定します。
ここでreverse()ではなくreverse_lazy()を使うのがポイントです。
reverse_lazy()は、URLの解決をクラスの定義時ではなく実際に呼び出されるタイミングまで遅らせてくれるので、urls.pyの読み込み順序に関するエラーを避けられます。
FBVとCBVの使い分け
比較表で見る判断軸
| 観点 | FBV | CBV |
|---|---|---|
| コードの見通し | 処理の流れが上から下に読める | 属性やメソッドが分散し、慣れが必要 |
| 定型処理(CRUD) | 毎回同じような記述が増えがち | 汎用ビューで大幅に短縮できる |
| 独自ロジックの追加 | 自由に書ける | メソッドのオーバーライドを理解する必要がある |
| 学習コスト | 低い | やや高い(継承・MROの理解が必要) |
どちらを選ぶべきか
判断に迷ったら、次の基準で決めるとよいでしょう。
- 一覧・詳細・CRUDなど定型的な処理が中心 → CBV
- 複数のモデルを横断する、条件分岐が複雑など独自性が強い処理 → FBV
- チームやプロジェクトの既存コードにどちらかが多い → それに合わせる
筆者の感覚では、初めてDjangoを触るうちはFBVで「リクエストとレスポンスの流れ」を体に染み込ませ、CRUD処理が増えてきたタイミングでCBVに乗り換えるのがスムーズです。
いきなりCBVから入ると、get_queryset()やget_context_data()といったオーバーライド対象のメソッドが多すぎて、何がどこで実行されているのか掴みにくいためです。
つまずきやすいポイント
get_context_data()の呼び忘れ
CBVでテンプレートに渡すデータを追加したいとき、get_context_data()をオーバーライドします。
❌ Before:super()を呼ばずに上書きしてしまう
class PostListView(ListView):
model = Post
def get_context_data(self, **kwargs):
context = {}
context["title"] = "投稿一覧"
return context
これだと、ListViewが本来用意してくれるobject_list(一覧データ)が失われてしまい、テンプレート側でpostsが空になります。
筆者も最初にこれをやってしまい、「一覧ページなのに1件も表示されない」というエラーに何十分も悩まされました。
✅ After:super().get_context_data()の結果に追記する
class PostListView(ListView):
model = Post
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "投稿一覧"
return context
super()で親クラスの処理結果を先に取得し、そこに必要な項目を追加する、という順番を必ず守ることが重要です。
まとめ
この記事のポイント
- CBVは
ListViewやDetailViewなどの汎用ビューを継承して書く - URLへの登録には
.as_view()が必要 - 定型的なCRUD処理はCBV、独自性の強い処理はFBVが向いている
get_context_data()を上書きするときは、必ずsuper()の戻り値をベースにする
次に読むべき記事
- Django Adminをカスタマイズして管理画面を使いこなす
- 関数ベースビュー(FBV)の書き方
- フォーム(forms.Form/ModelForm)でバリデーションを実装する
タグ: Django, 中級者向け, フレームワーク基礎