クラスベースのビューの概要—Djangoのドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/topics/class-based-views/intro
移動先:案内検索

クラスベースのビューの概要

クラスベースのビューは、関数ではなくPythonオブジェクトとしてビューを実装するための代替方法を提供します。 これらは関数ベースのビューに置き換わるものではありませんが、関数ベースのビューと比較した場合、特定の違いと利点があります。

  • 特定のHTTPメソッド(GETPOSTなど)に関連するコードの編成は、条件分岐の代わりに個別のメソッドでアドレス指定できます。
  • ミックスイン(多重継承)などのオブジェクト指向技術を使用して、コードを再利用可能なコンポーネントに分解できます。

ジェネリックビュー、クラスベースのビュー、およびクラスベースのジェネリックビューの関係と履歴

最初はビュー関数コントラクトしかありませんでしたが、Djangoは関数に HttpRequest を渡し、 HttpResponse を返すことを期待していました。 これは、Djangoが提供した範囲でした。

早い段階で、ビューの開発に共通のイディオムとパターンが見られることが認識されていました。 これらのパターンを抽象化し、一般的なケースのビュー開発を容易にするために、関数ベースの汎用ビューが導入されました。

関数ベースのジェネリックビューの問題は、単純なケースを十分にカバーしているものの、一部の構成オプションを超えて拡張またはカスタマイズする方法がなく、多くの実際のアプリケーションでの有用性が制限されていることです。

クラスベースのジェネリックビューは、ビューの開発を容易にするために、関数ベースのジェネリックビューと同じ目的で作成されました。 ただし、ミックスインを使用したソリューションの実装方法は、クラスベースのジェネリックビューが関数ベースのビューよりも拡張性と柔軟性を高めるツールキットを提供します。

過去に関数ベースのジェネリックビューを試したことがあり、それらが不足していることがわかった場合は、クラスベースのジェネリックビューをクラスベースの同等のものとしてではなく、ジェネリックビューが意図していた元の問題を解決するための新しいアプローチとして考える必要があります。解決。

Djangoがクラスベースのジェネリックビューを構築するために使用する基本クラスとミックスインのツールキットは、最大限の柔軟性を実現するように構築されているため、デフォルトのメソッド実装と属性の形で多くのフックがあり、最も単純な使用では関係しません。ケース。 たとえば、form_classのクラスベースの属性に制限する代わりに、実装はget_formメソッドを使用します。このメソッドはget_form_classメソッドを呼び出します。このメソッドはデフォルトの実装でクラスのform_class属性。 これにより、属性から完全に動的で呼び出し可能なフックまで、使用するフォームを指定するためのいくつかのオプションが提供されます。 これらのオプションは、単純な状況では中空の複雑さを追加するように見えますが、これらのオプションがないと、より高度な設計が制限されます。


クラスベースのビューの使用

基本的に、クラスベースのビューを使用すると、単一のビュー関数内でコードを条件付きで分岐する代わりに、さまざまなクラスインスタンスメソッドを使用してさまざまなHTTPリクエストメソッドに応答できます。

したがって、ビュー関数でHTTP GETを処理するコードは次のようになります。

from django.http import HttpResponse

def my_view(request):
    if request.method == 'GET':
        # <view logic>
        return HttpResponse('result')

クラスベースのビューでは、これは次のようになります。

from django.http import HttpResponse
from django.views import View

class MyView(View):
    def get(self, request):
        # <view logic>
        return HttpResponse('result')

DjangoのURLリゾルバーは、リクエストと関連する引数をクラスではなく呼び出し可能な関数に送信することを想定しているため、クラスベースのビューには、リクエストの到着時に呼び出すことができる関数を返す as_view()クラスメソッドがあります。関連するパターンに一致するURLの場合。 この関数は、クラスのインスタンスを作成し、 setup()を呼び出して属性を初期化してから、 dispatch()メソッドを呼び出します。 dispatchは、リクエストを調べてGETPOSTなどであるかどうかを判断し、一致するメソッドが定義されている場合はリクエストを中継するか、を発生させます。そうでない場合はHttpResponseNotAllowed

# urls.py
from django.urls import path
from myapp.views import MyView

urlpatterns = [
    path('about/', MyView.as_view()),
]

メソッドが返すものは、関数ベースのビューから返すもの、つまり HttpResponse の形式と同じであることに注意してください。 これは、 httpショートカットまたは TemplateResponse オブジェクトがクラスベースのビュー内で使用できることを意味します。

最小限のクラスベースのビューでは、ジョブを実行するためにクラス属性は必要ありませんが、クラス属性は多くのクラスベースの設計で役立ち、クラス属性を構成または設定する方法は2つあります。

1つ目は、サブクラス内の属性とメソッドをサブクラス化してオーバーライドする標準のPythonの方法です。 したがって、親クラスに次のような属性greetingがある場合:

from django.http import HttpResponse
from django.views import View

class GreetingView(View):
    greeting = "Good Day"

    def get(self, request):
        return HttpResponse(self.greeting)

サブクラスでそれをオーバーライドできます。

class MorningGreetingView(GreetingView):
    greeting = "Morning to ya"

別のオプションは、URLconfの as_view()呼び出しのキーワード引数としてクラス属性を構成することです。

urlpatterns = [
    path('about/', GreetingView.as_view(greeting="G'day")),
]

ノート

クラスは、ディスパッチされたリクエストごとにインスタンス化されますが、 as_view()エントリポイントを介して設定されたクラス属性は、URLのインポート時に一度だけ構成されます。


ミックスインの使用

ミックスインは、複数の親クラスの動作と属性を組み合わせることができる多重継承の形式です。

たとえば、ジェネリッククラスベースのビューには、 TemplateResponseMixin というミックスインがあり、その主な目的はメソッド render_to_response()を定義することです。 View 基本クラスの動作と組み合わせると、結果は TemplateView クラスになり、適切なマッチングメソッドにリクエストをディスパッチします(Viewで定義された動作)。基本クラス)であり、 template_name 属性を使用して TemplateResponse オブジェクト( [で定義された動作)を返す render_to_response()メソッドがあります。 X396X])。

ミックスインは、複数のクラス間でコードを再利用するための優れた方法ですが、ある程度のコストがかかります。 コードがミックスインに散在しているほど、子クラスを読み取ってそれが何をしているのかを正確に知ることが難しくなり、深い継承ツリー。

また、1つの汎用ビューからのみ継承できることにも注意してください。つまり、 View から継承できる親クラスは1つだけで、残り(存在する場合)はミックスインである必要があります。 Viewから継承する複数のクラスから継承しようとしています-たとえば、リストの一番上にあるフォームを使用して、 ProcessFormViewListView を組み合わせようとしています-期待どおりに動作しません。


クラスベースのビューを使用したフォームの処理

フォームを処理する基本的な関数ベースのビューは、次のようになります。

from django.http import HttpResponseRedirect
from django.shortcuts import render

from .forms import MyForm

def myview(request):
    if request.method == "POST":
        form = MyForm(request.POST)
        if form.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')
    else:
        form = MyForm(initial={'key': 'value'})

    return render(request, 'form_template.html', {'form': form})

同様のクラスベースのビューは次のようになります。

from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View

from .forms import MyForm

class MyFormView(View):
    form_class = MyForm
    initial = {'key': 'value'}
    template_name = 'form_template.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class(initial=self.initial)
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')

        return render(request, self.template_name, {'form': form})

これは最小限のケースですが、クラス属性のいずれかをオーバーライドすることで、このビューをカスタマイズするオプションがあることがわかります。 form_class、URLconf構成を介して、または1つ以上のメソッド(または両方!)をサブクラス化してオーバーライドします。


クラスベースのビューの装飾

クラスベースのビューの拡張は、ミックスインの使用に限定されません。 デコレータを使用することもできます。 クラスベースのビューは関数ではないため、as_view()を使用しているか、サブクラスを作成しているかによって、ビューの装飾の動作が異なります。

URLconfで飾る

as_view()メソッドの結果を装飾することにより、クラスベースのビューを調整できます。 これを行う最も簡単な場所は、ビューをデプロイするURLconfです。

from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView

from .views import VoteView

urlpatterns = [
    path('about/', login_required(TemplateView.as_view(template_name="secret.html"))),
    path('vote/', permission_required('polls.can_vote')(VoteView.as_view())),
]

このアプローチは、インスタンスごとにデコレータを適用します。 ビューのすべてのインスタンスを装飾する場合は、別のアプローチをとる必要があります。


クラスを飾る

クラスベースのビューのすべてのインスタンスを装飾するには、クラス定義自体を装飾する必要があります。 これを行うには、クラスの dispatch()メソッドにデコレータを適用します。

クラスのメソッドはスタンドアロン関数とまったく同じではないため、関数デコレータをメソッドに適用するだけでは不十分です。最初にメソッドデコレータに変換する必要があります。 method_decoratorデコレータは、関数デコレータをメソッドデコレータに変換して、インスタンスメソッドで使用できるようにします。 例えば:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class ProtectedView(TemplateView):
    template_name = 'secret.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

または、より簡潔に言えば、代わりにクラスを装飾し、装飾するメソッドの名前をキーワード引数nameとして渡すことができます。

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

複数の場所で使用される一般的なデコレータのセットがある場合は、デコレータのリストまたはタプルを定義して、method_decorator()を複数回呼び出す代わりにこれを使用できます。 これらの2つのクラスは同等です。

decorators = [never_cache, login_required]

@method_decorator(decorators, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

@method_decorator(never_cache, name='dispatch')
@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

デコレータは、デコレータに渡された順序でリクエストを処理します。 この例では、never_cache()login_required()の前にリクエストを処理します。

この例では、ProtectedViewのすべてのインスタンスにログイン保護があります。 これらの例ではlogin_requiredを使用していますが、 LoginRequiredMixin を使用しても同じ動作を得ることができます。

ノート

method_decoratorは、*args**kwargsをパラメーターとしてクラスのdecoratedメソッドに渡します。 メソッドが互換性のあるパラメーターのセットを受け入れない場合、TypeError例外が発生します。