【Django】関数ベースビュー(FBV)の書き方

Django

こんにちは、かつコーチです。

前回の記事でurls.pyからviews.pyの処理を呼び出す流れを紹介しましたが、今回はその「処理」そのものを担当するViewの書き方を詳しく解説します。
Djangoには2種類のViewの書き方があり、その1つが今回扱う関数ベースビュー(FBV: Function-Based View)です。

関数ベースビューとは?

関数として定義するシンプルなView

関数ベースビュー(FBV)とは、その名の通り、Pythonの関数としてViewを定義する書き方です。
リクエストを受け取り、何らかの処理をして、レスポンスを返す、という一連の流れを1つの関数の中に素直に書けるのが特徴です。

# blog/views.py
from django.http import HttpResponse

def index(request):
    return HttpResponse("こんにちは、Djangoの世界へ")

引数のrequestには、ブラウザから送られてきたリクエストの情報(GETパラメータ、POSTデータ、ユーザー情報など)がすべて詰まっています。

もう1つの書き方「クラスベースビュー(CBV)」との違い

DjangoにはFBVのほかに、クラスベースビュー(CBV: Class-Based View)という書き方も用意されています。
CBVはクラスを使ってViewを定義する方法で、共通処理をまとめやすいというメリットがありますが、初心者にはやや抽象度が高く感じられることがあります。

項目FBVCBV
書き方関数クラス
可読性処理の流れが上から下に追いやすい継承関係を理解する必要がある
向いている場面シンプルな処理、条件分岐が複雑な処理一覧・詳細・作成・更新など定型的な処理

まずはFBVで「Viewが何をしているか」を体で理解してから、CBVに進むのがおすすめの学習順序です。
CBVの詳しい使い方は、この後の記事「クラスベースビュー(CBV)の基本と使いどころ」で扱います。

FBVの基本の書き方

GETリクエストを処理する

まずは最もシンプルな、一覧ページを表示するFBVを書いてみましょう。

# blog/views.py
from django.shortcuts import render

def index(request):
    context = {
        "title": "ブログ記事一覧",
        "posts": ["1本目の記事", "2本目の記事", "3本目の記事"],
    }
    return render(request, "blog/index.html", context)

render()関数は、指定したテンプレートにcontext(テンプレートに渡すデータの辞書)を渡してHTMLを組み立て、レスポンスとして返してくれる便利な関数です。
テンプレート側では、次のようにcontextに渡したデータを表示できます。

<!-- blog/templates/blog/index.html -->
<h1>{{ title }}</h1>
<ul>
  {% for post in posts %}
    <li>{{ post }}</li>
  {% endfor %}
</ul>

リクエストメソッドで処理を分岐する

フォームの送信を受け取るViewでは、GETとPOSTで処理を分けるのが基本パターンです。

# blog/views.py
from django.shortcuts import render, redirect

def contact(request):
    if request.method == "POST":
        name = request.POST.get("name")
        # 本来はここでバリデーションや保存処理を行う
        return redirect("blog:index")
    return render(request, "blog/contact.html")

request.methodで現在のリクエストがGETかPOSTかを判定し、request.POST.get("name")のようにフォームから送られてきたデータを取得します。

404エラーを自分で制御する

存在しないデータへのアクセスに対しては、get_object_or_404を使うと簡潔に書けます。

# blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post

def detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, "blog/detail.html", {"post": post})

get_object_or_404は、指定したデータが存在すればそのまま返し、存在しなければ自動的に404エラーページを表示してくれる便利な関数です。

つまずきやすい設定・注意点

render()の第2引数のパス指定を間違える

テンプレートのパス指定でつまずくケースはとても多いです。
Djangoはsettings.pyTEMPLATES設定に基づいてテンプレートを探すため、アプリ名を含めたフォルダ構成にしておくのが一般的です。

blog/
└── templates/
    └── blog/          ← アプリ名と同じ名前のフォルダを挟む
        └── index.html

このように、あえてblog/templates/blog/と2階層にアプリ名を重ねるのが慣習になっています。
これを知らずにblog/templates/index.htmlと直接置いてしまうと、別のアプリの同名テンプレートと衝突するリスクがあるため注意が必要です。

よくあるつまずきポイント・エラー対処

TemplateDoesNotExistエラーが出る

❌ Before
TemplateDoesNotExist at /blog/
blog/index.html

これは、テンプレートファイルが見つからない、もしくはフォルダ構成が間違っているときに出るエラーです。

✅ After
# config/settings.py のINSTALLED_APPSに、
# テンプレートを持つアプリ(blog)が登録されているか確認する
INSTALLED_APPS = [
    # ...
    "blog",
]

筆者もこのエラーに何度も遭遇しましたが、原因のほとんどは「アプリをINSTALLED_APPSに登録し忘れている」か「テンプレートのフォルダ階層を間違えている」のどちらかでした。
エラーが出たら、まずこの2点を疑うと解決が早くなります。

request.POST.get()の代わりにrequest.POST[]を使ってエラーになる

❌ Before
name = request.POST["name"]
# KeyError: 'name'
# フォームにname項目がない場合、そのままエラーで落ちてしまう
✅ After
name = request.POST.get("name", "")
# 項目がなくても空文字を返し、エラーにならない

request.POST["name"]は辞書のキーアクセスと同じ書き方のため、キーが存在しないとその場でエラーになります。
get()メソッドを使い、デフォルト値を指定しておくと、想定外の入力に対しても安全に処理できます。

応用・一歩先の使い方

デコレータでアクセス制限をかける

FBVは関数なので、デコレータ(関数の前後に処理を付け加える仕組み)を使って、ログインしていないユーザーのアクセスを制限するといったことも簡単に書けます。

# blog/views.py
from django.contrib.auth.decorators import login_required

@login_required
def create(request):
    return render(request, "blog/create.html")

@login_requiredを付けるだけで、未ログインのユーザーがアクセスした場合は自動的にログインページへリダイレクトされます。
このシンプルさは、関数ベースビューならではの書きやすさと言えるでしょう。

まとめ

この記事のポイント

  • 関数ベースビュー(FBV)は、Viewを素直な関数として定義する書き方
  • render()でテンプレートにデータを渡し、request.methodでGET/POSTを判定する
  • テンプレートは「アプリ名/templates/アプリ名/」の2階層構成にするのが慣習
  • get_object_or_404やデコレータを使うと、定型処理を簡潔に書ける

次に読むべき記事

FBVの書き方が分かったら、次はもう1つのViewの書き方である「クラスベースビュー(CBV)の基本と使いどころ」に進み、定型的な処理をより効率的に書く方法を学んでいきましょう。

タグ: Django, 初心者向け, フレームワーク基礎

タイトルとURLをコピーしました