(mixins.pyへのリンク) (generics.pyへのリンク)

汎用ビュー

Djangoの汎用ビューは、一般的な使用パターンを短縮するために開発されました。ビュー開発で見られる特定の慣用句やパターンを取り込み、抽象化することで、データの一般的なビューを繰り返し記述することなく、迅速に記述できます。

— Djangoドキュメント(へのリンク)

クラスベースビューの主な利点の1つは、再利用可能な動作の断片を組み合わせることができる方法です。REST frameworkは、一般的に使用されるパターンを提供する、多数の組み込みビューを提供することで、この利点を活用しています。

REST frameworkが提供する汎用ビューを使用すると、データベースモデルに密接にマッピングするAPIビューを迅速に構築できます。

汎用ビューがAPIのニーズに合わない場合は、通常のAPIViewクラスを使用するか、汎用ビューで使用されるMixinと基底クラスを再利用して、独自の再利用可能な汎用ビューのセットを作成できます。

通常、汎用ビューを使用する場合は、ビューをオーバーライドし、いくつかのクラス属性を設定します。

from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]

より複雑な場合は、ビュークラスのさまざまなメソッドをオーバーライドすることもできます。例えば。

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]

    def list(self, request):
        # Note the use of `get_queryset()` instead of `self.queryset`
        queryset = self.get_queryset()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

非常に単純な場合は、.as_view()メソッドを使用して、クラス属性を渡すことができます。たとえば、URLconfには次のようなエントリが含まれる場合があります。

path('users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')

APIリファレンス

GenericAPIView

このクラスは、REST frameworkのAPIViewクラスを拡張し、標準のリストビューと詳細ビューに一般的に必要な動作を追加します。

提供される具体的な汎用ビューはそれぞれ、GenericAPIViewと1つ以上のMixinクラスを組み合わせて構築されています。

属性

基本設定:

次の属性は、基本的なビューの動作を制御します。

  • queryset - このビューからオブジェクトを返すために使用されるクエリセット。通常、この属性を設定するか、get_queryset()メソッドをオーバーライドする必要があります。ビューメソッドをオーバーライドする場合は、このプロパティに直接アクセスする代わりに、get_queryset()を呼び出すことが重要です。 querysetは一度評価され、その結果が後続のすべてのリクエストのためにキャッシュされるためです。
  • serializer_class - 入力の検証とデシリアライズ、および出力のシリアライズに使用されるシリアライザークラス。通常、この属性を設定するか、get_serializer_class()メソッドをオーバーライドする必要があります。
  • lookup_field - 個々のモデルインスタンスのオブジェクトルックアップを実行するために使用されるモデルフィールド。デフォルトは'pk'です。ハイパーリンクAPIを使用する場合は、カスタム値を使用する必要がある場合、APIビューとシリアライザークラスの*両方*でルックアップフィールドを設定する必要があることに注意してください。
  • lookup_url_kwarg - オブジェクトルックアップに使用されるURLキーワード引数。URLconfには、この値に対応するキーワード引数が含まれている必要があります。設定されていない場合、デフォルトではlookup_fieldと同じ値が使用されます。

ページネーション:

次の属性は、リストビューで使用する場合のページネーションを制御するために使用されます。

  • pagination_class - リスト結果をページネーションする際に使用されるページネーションクラス。デフォルトはDEFAULT_PAGINATION_CLASS設定と同じ値で、'rest_framework.pagination.PageNumberPagination'です。 pagination_class=Noneを設定すると、このビューのページネーションが無効になります。

フィルタリング:

  • filter_backends - クエリセットのフィルタリングに使用されるフィルターバックエンドクラスのリスト。 デフォルトは `DEFAULT_FILTER_BACKENDS` 設定と同じ値です.

メソッド

基本メソッド:

get_queryset(self)

リストビューに使用されるクエリセットと、詳細ビューのルックアップの基盤として使用されるクエリセットを返します。デフォルトでは、queryset属性で指定されたクエリセットを返します。

self.querysetは一度だけ評価され、その結果が後続のすべてのリクエストのためにキャッシュされるため、このメソッドは常にself.querysetに直接アクセスするのではなく使用する必要があります。

リクエストを行っているユーザーに固有のクエリセットを返すなど、動的な動作を提供するためにオーバーライドできます。

例えば

def get_queryset(self):
    user = self.request.user
    return user.accounts.all()

**注意:** 汎用ビューで使用される `serializer_class` が ORM リレーションにまたがり、n+1 問題が発生する場合、このメソッドで `select_related` と `prefetch_related` を使用してクエリセットを最適化できます。n+1 問題と、上記のメソッドのユースケースの詳細については、Django ドキュメント の関連セクションを参照してください。


get_object(self)

詳細ビューに使用されるオブジェクトインスタンスを返します。デフォルトでは、lookup_fieldパラメータを使用して基本クエリセットをフィルタリングします。

複数のURLキーワード引数に基づくオブジェクトルックアップなど、より複雑な動作を提供するためにオーバーライドできます。

例えば

def get_object(self):
    queryset = self.get_queryset()
    filter = {}
    for field in self.multiple_lookup_fields:
        filter[field] = self.kwargs[field]

    obj = get_object_or_404(queryset, **filter)
    self.check_object_permissions(self.request, obj)
    return obj

APIにオブジェクトレベルのパーミッションが含まれていない場合は、オプションでself.check_object_permissionsを除外し、get_object_or_404ルックアップからオブジェクトを返すことができます。

filter_queryset(self, queryset)

指定されたクエリセットを、使用中のフィルターバックエンドでフィルタリングし、新しいクエリセットを返します。

例えば

def filter_queryset(self, queryset):
    filter_backends = [CategoryFilter]

    if 'geo_route' in self.request.query_params:
        filter_backends = [GeoRouteFilter, CategoryFilter]
    elif 'geo_point' in self.request.query_params:
        filter_backends = [GeoPointFilter, CategoryFilter]

    for backend in list(filter_backends):
        queryset = backend().filter_queryset(self.request, queryset, view=self)

    return queryset

get_serializer_class(self)

シリアライザーに使用されるクラスを返します。デフォルトでは、serializer_class属性を返します.

読み取り操作と書き込み操作に異なるシリアライザーを使用する、または異なるタイプのユーザーに異なるシリアライザーを提供するなど、動的な動作を提供するためにオーバーライドできます。

例えば

def get_serializer_class(self):
    if self.request.user.is_staff:
        return FullAccountSerializer
    return BasicAccountSerializer

保存と削除のフック:

以下のメソッドはMixinクラスによって提供され、オブジェクトの保存または削除の動作を簡単にオーバーライドできます。

  • perform_create(self, serializer) - 新しいオブジェクトインスタンスを保存するときにCreateModelMixinによって呼び出されます。
  • perform_update(self, serializer) - 既存のオブジェクトインスタンスを保存するときにUpdateModelMixinによって呼び出されます。
  • perform_destroy(self, instance) - オブジェクトインスタンスを削除するときにDestroyModelMixinによって呼び出されます。

これらのフックは、リクエストに暗黙的に含まれているが、リクエストデータの一部ではない属性を設定するのに特に役立ちます。たとえば、リクエストユーザーに基づいて、またはURLキーワード引数に基づいて、オブジェクトに属性を設定できます。

def perform_create(self, serializer):
    serializer.save(user=self.request.user)

これらのオーバーライドポイントは、確認メールを送信したり、更新をログに記録したりするなど、オブジェクトの保存前または保存後に行われる動作を追加するのにも特に役立ちます。

def perform_update(self, serializer):
    instance = serializer.save()
    send_email_confirmation(user=self.request.user, modified=instance)

ValidationError()を発生させることにより、これらのフックを使用して追加の検証を提供することもできます。これは、データベース保存時に適用する必要がある検証ロジックがある場合に役立ちます。例えば

def perform_create(self, serializer):
    queryset = SignupRequest.objects.filter(user=self.request.user)
    if queryset.exists():
        raise ValidationError('You have already signed up')
    serializer.save(user=self.request.user)

その他のメソッド:

通常、以下のメソッドをオーバーライドする必要はありませんが、GenericAPIViewを使用してカスタムビューを作成する場合は、これらのメソッドを呼び出す必要がある場合があります。

  • get_serializer_context(self) - シリアライザーに提供する必要がある追加のコンテキストを含む辞書を返します。デフォルトでは、'request''view'、および'format'キーが含まれます。
  • get_serializer(self, instance=None, data=None, many=False, partial=False) - シリアライザーインスタンスを返します。
  • get_paginated_response(self, data) - ページネーションスタイルのResponseオブジェクトを返します。
  • paginate_queryset(self, queryset) - 必要に応じてクエリセットをページネーションし、ページオブジェクトを返すか、このビューにページネーションが設定されていない場合はNoneを返します.
  • `filter_queryset(self, queryset)` - 指定されたクエリセットに対し、使用中のフィルターバックエンドでフィルタリングを行い、新しいクエリセットを返します.

Mixin

Mixinクラスは、基本的なビューの動作を提供するために使用されるアクションを提供します。Mixinクラスは、.get().post()などのハンドラーメソッドを直接定義するのではなく、アクションメソッドを提供することに注意してください。これにより、動作をより柔軟に構成できます。

Mixinクラスは、rest_framework.mixinsからインポートできます。

ListModelMixin

クエリセットのリストを実装する.list(request, *args, **kwargs)メソッドを提供します。

クエリセットが設定されている場合、これは200 OKレスポンスを返し、レスポンスの本文としてクエリセットのシリアライズされた表現を含みます。レスポンスデータは、オプションでページネーションできます。

CreateModelMixin

新しいモデルインスタンスの作成と保存を実装する.create(request, *args, **kwargs)メソッドを提供します。

オブジェクトが作成された場合、201 Createdレスポンスが返され、レスポンスの本文にはオブジェクトのシリアライズされた表現が含まれます。表現にurlという名前のキーが含まれている場合、レスポンスのLocationヘッダーにはその値が設定されます。

オブジェクトの作成に提供されたリクエストデータが無効な場合、400 Bad Requestレスポンスが返され、レスポンスの本文にはエラーの詳細が含まれます。

RetrieveModelMixin

既存のモデルインスタンスをレスポンスで返すことを実装する.retrieve(request, *args, **kwargs)メソッドを提供します。

オブジェクトを取得できる場合、200 OKレスポンスが返され、レスポンスの本文にはオブジェクトのシリアライズされた表現が含まれます。それ以外の場合は、404 Not Foundが返されます。

UpdateModelMixin

既存のモデルインスタンスの更新と保存を実装する.update(request, *args, **kwargs)メソッドを提供します。

また、.partial_update(request, *args, **kwargs)メソッドも提供します。これはupdateメソッドと似ていますが、更新のすべてのフィールドがオプションである点が異なります。これにより、HTTP PATCHリクエストがサポートされます。

オブジェクトが更新された場合、200 OKレスポンスが返され、レスポンスの本文にはオブジェクトのシリアライズされた表現が含まれます。

オブジェクトの更新に提供されたリクエストデータが無効な場合、400 Bad Requestレスポンスが返され、レスポンスの本文にはエラーの詳細が含まれます。

DestroyModelMixin

既存のモデルインスタンスの削除を実装する.destroy(request, *args, **kwargs)メソッドを提供します。

オブジェクトが削除された場合、204 No Contentレスポンスが返されます。それ以外の場合は、404 Not Foundが返されます。


具象ビュークラス

以下のクラスは具体的な汎用ビューです。汎用ビューを使用する場合、高度にカスタマイズされた動作が必要でない限り、通常はこのレベルで作業することになります。

ビュークラスはrest_framework.genericsからインポートできます。

CreateAPIView

**作成専用**エンドポイントに使用されます。

postメソッドハンドラーを提供します。

拡張:GenericAPIViewCreateModelMixin

ListAPIView

**モデルインスタンスのコレクション**を表す**読み取り専用**エンドポイントに使用されます。

getメソッドハンドラーを提供します。

拡張:GenericAPIViewListModelMixin

RetrieveAPIView

**単一のモデルインスタンス**を表す**読み取り専用**エンドポイントに使用されます。

getメソッドハンドラーを提供します。

拡張:GenericAPIViewRetrieveModelMixin

DestroyAPIView

**単一のモデルインスタンス**の**削除専用**エンドポイントに使用されます。

deleteメソッドハンドラーを提供します。

拡張:GenericAPIViewDestroyModelMixin

UpdateAPIView

**単一のモデルインスタンス**の**更新専用**エンドポイントに使用されます。

putおよびpatchメソッドハンドラーを提供します。

拡張:GenericAPIViewUpdateModelMixin

ListCreateAPIView

**モデルインスタンスのコレクション**を表す**読み取り/書き込み**エンドポイントに使用されます。

getおよびpostメソッドハンドラーを提供します。

拡張:GenericAPIViewListModelMixinCreateModelMixin

RetrieveUpdateAPIView

**単一のモデルインスタンス**を表す**読み取りまたは更新**エンドポイントに使用されます。

getput、およびpatchメソッドハンドラーを提供します。

拡張:GenericAPIViewRetrieveModelMixinUpdateModelMixin

RetrieveDestroyAPIView

**単一のモデルインスタンス**を表す**読み取りまたは削除**エンドポイントに使用されます。

getおよびdeleteメソッドハンドラーを提供します。

拡張:GenericAPIViewRetrieveModelMixinDestroyModelMixin

RetrieveUpdateDestroyAPIView

**単一のモデルインスタンス**を表す**読み取り/書き込み/削除**エンドポイントに使用されます。

getputpatch、およびdeleteメソッドハンドラーを提供します。

拡張:GenericAPIViewRetrieveModelMixinUpdateModelMixinDestroyModelMixin


汎用ビューのカスタマイズ

多くの場合、既存の汎用ビューを使用しますが、わずかにカスタマイズされた動作を使用します。複数の場所でカスタマイズされた動作の一部を再利用している場合は、その動作を共通クラスにリファクタリングして、必要なビューまたはビューセットに適用することができます。

カスタムMixinの作成

たとえば、URL設定で複数のフィールドに基づいてオブジェクトを検索する必要がある場合は、次のようなmixinクラスを作成できます。

class MultipleFieldLookupMixin:
    """
    Apply this mixin to any view or viewset to get multiple field filtering
    based on a `lookup_fields` attribute, instead of the default single field filtering.
    """
    def get_object(self):
        queryset = self.get_queryset()             # Get the base queryset
        queryset = self.filter_queryset(queryset)  # Apply any filter backends
        filter = {}
        for field in self.lookup_fields:
            if self.kwargs.get(field): # Ignore empty fields.
                filter[field] = self.kwargs[field]
        obj = get_object_or_404(queryset, **filter)  # Lookup the object
        self.check_object_permissions(self.request, obj)
        return obj

カスタム動作を適用する必要があるときはいつでも、このmixinをビューまたはビューセットに適用するだけです。

class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    lookup_fields = ['account', 'username']

カスタムmixinを使用することは、使用する必要があるカスタム動作がある場合に適したオプションです。

カスタム基底クラスの作成

複数のビューでmixinを使用している場合は、さらに一歩進んで、プロジェクト全体で使用できる独自のベースビューセットを作成できます。例えば

class BaseRetrieveView(MultipleFieldLookupMixin,
                       generics.RetrieveAPIView):
    pass

class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin,
                                    generics.RetrieveUpdateDestroyAPIView):
    pass

カスタムベースクラスを使用することは、プロジェクト全体の多数のビューでカスタム動作を一貫して繰り返す必要がある場合に適したオプションです。


PUTによる作成

バージョン3.0より前では、REST frameworkのmixinは、オブジェクトが既に存在するかどうかによって、PUTを更新操作または作成操作として扱っていました。

PUTを作成操作として許可すると、オブジェクトの有無に関する情報が必然的に公開されるため、問題が発生します。また、以前に削除されたインスタンスの再作成を透過的に許可することが、単に404レスポンスを返すよりも必ずしも優れたデフォルトの動作であるとは限りません。

PUT as 404」と「PUT as create」の両方のスタイルは、状況によって有効ですが、バージョン3.0以降は、よりシンプルで明白であるため、404の動作をデフォルトで使用しています。

汎用的なPUT-as-create動作が必要な場合は、このAllowPUTAsCreateMixinクラスのようなものをビューにmixinとして含めることができます。


サードパーティパッケージ

以下のサードパーティパッケージは、追加の汎用ビュー実装を提供します。

Django Rest Multiple Models

Django Rest Multiple Modelsは、単一のAPIリクエストを介して複数のシリアライズされたモデルやクエリセットを送信するための汎用ビュー(およびmixin)を提供します。