5.

Django クラスベースビュー (CBV) で GET / POST を受け取る方法|View / FormView

編集
この記事の要点
  • Django のクラスベースビュー (CBV) で GET / POST リクエストを受ける方法
  • 基本: View 継承 + get() / post() メソッドを定義
  • フォーム処理: FormViewform_valid() / form_invalid() を提供
  • CRUD: CreateView / UpdateView / DeleteView / ListView / DetailView
  • 関数ベースビュー (FBV) と比べて再利用性が高い反面、暗黙の処理が多い

基本: View クラスを継承

# views.py
from django.views import View
from django.shortcuts import render, redirect

class ContactView(View):

    # GET リクエスト
    def get(self, request):
        return render(request, 'contact.html', {
            'form_data': None,
        })

    # POST リクエスト
    def post(self, request):
        name = request.POST.get('name', '')
        email = request.POST.get('email', '')

        if not name or not email:
            return render(request, 'contact.html', {
                'error': '入力エラー',
                'form_data': request.POST,
            })

        # 処理(DB 保存・メール送信等)
        return redirect('contact_thanks')
# urls.py
from django.urls import path
from .views import ContactView

urlpatterns = [
    # ★ as_view() を忘れずに
    path('contact/', ContactView.as_view(), name='contact'),
]

関数ベースビュー (FBV) との比較

# FBV (関数ベース) - シンプル
def contact(request):
    if request.method == 'GET':
        return render(request, 'contact.html')
    elif request.method == 'POST':
        # ... 処理
        return redirect('contact_thanks')

# CBV (クラスベース) - 構造化
class ContactView(View):
    def get(self, request):
        return render(request, 'contact.html')
    def post(self, request):
        # ... 処理
        return redirect('contact_thanks')
FBV (関数)CBV (クラス)
シンプルさ○ 学習コスト低△ 慣れが必要
再利用性△ コピペ気味に○ 継承・Mixin で共通化
標準機能すべて自分で書くCreateView / UpdateView 等が便利
カスタマイズ明示的メソッドオーバーライドで柔軟
デバッグ追いやすいクラス階層を辿る必要

FormView でフォーム処理

Django Forms と組み合わせるなら FormView が便利:

# forms.py
from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)

# views.py
from django.views.generic.edit import FormView
from django.urls import reverse_lazy

class ContactView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm
    success_url = reverse_lazy('contact_thanks')

    def form_valid(self, form):
        # フォームが正しく送信された場合
        name = form.cleaned_data['name']
        email = form.cleaned_data['email']
        # ... メール送信等

        return super().form_valid(form)  # success_url にリダイレクト

    def form_invalid(self, form):
        # バリデーションエラー時(自動でテンプレート再表示)
        return super().form_invalid(form)

CRUD ジェネリックビュー

from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Article
from .forms import ArticleForm

# 一覧
class ArticleListView(ListView):
    model = Article
    template_name = 'article/list.html'      # デフォルト: /_list.html
    context_object_name = 'articles'         # デフォルト: object_list
    paginate_by = 20                         # ページネーション

    def get_queryset(self):
        qs = super().get_queryset()
        return qs.filter(published=True).order_by('-created_at')

# 詳細
class ArticleDetailView(DetailView):
    model = Article                          # URL に  または  必要
    # /articles// → object として渡される

# 新規作成
class ArticleCreateView(CreateView):
    model = Article
    form_class = ArticleForm
    template_name = 'article/form.html'
    success_url = reverse_lazy('article_list')

    def form_valid(self, form):
        form.instance.author = self.request.user  # ログインユーザを著者に
        return super().form_valid(form)

# 編集
class ArticleUpdateView(UpdateView):
    model = Article
    form_class = ArticleForm
    template_name = 'article/form.html'
    success_url = reverse_lazy('article_list')

# 削除
class ArticleDeleteView(DeleteView):
    model = Article
    template_name = 'article/confirm_delete.html'
    success_url = reverse_lazy('article_list')

Mixin で機能追加

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin

# ログイン必須
class ArticleCreateView(LoginRequiredMixin, CreateView):
    model = Article
    form_class = ArticleForm
    login_url = '/login/'  # 未ログイン時のリダイレクト先

# 作者本人のみ編集可
class ArticleUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = Article
    form_class = ArticleForm

    def test_func(self):
        article = self.get_object()
        return self.request.user == article.author

カスタムメソッドのオーバーライドポイント

メソッド用途
get_queryset()絞り込み・ソート
get_context_data()テンプレートに追加データを渡す
get_object()取得する単一オブジェクトのカスタマイズ
get_form_kwargs()Form 初期化引数のカスタマイズ
form_valid() / form_invalid()バリデーション後の処理
dispatch()すべてのリクエストの前処理
get_success_url()動的なリダイレクト先

dispatch() で共通処理

class MyView(View):

    def dispatch(self, request, *args, **kwargs):
        # GET / POST 共通の前処理
        if not request.session.get('foo'):
            return redirect('login')
        return super().dispatch(request, *args, **kwargs)

    def get(self, request):
        ...
    def post(self, request):
        ...

URL での as_view() 引数

# 引数で属性をオーバーライド可能
urlpatterns = [
    path('articles/', ArticleListView.as_view(paginate_by=10), name='list_10'),
    path('news/',     ArticleListView.as_view(paginate_by=50, template_name='news.html')),
]

関連

  • RedirectView: シンプルなリダイレクト専用
  • TemplateView: 静的テンプレート専用
  • DRF の APIView / GenericAPIView: REST API 用
  • django-extensions の show_urls: 全 URL とビューの一覧表示
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. クラスベースビュー(主流)の作り方とviewの分割
  2. 関数ベースビューの作り方とviewの分割
  3. URLディスパッチャー(ルーティング処理)
  4. GETとPOSTパラメータ受け取り
  5. クラスベースビューでGET/POSTリクエストの受け取り方
  6. クラスベースビューでテンプレートに値を渡す方法
  7. ビューでリダイレクト
  8. cookieの値の設定と取得
  9. HTTPステータスコードの返し方

最近更新/作成されたページ