汎用ビュー
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
メソッドハンドラーを提供します。
拡張:GenericAPIView、CreateModelMixin
ListAPIView
**モデルインスタンスのコレクション**を表す**読み取り専用**エンドポイントに使用されます。
get
メソッドハンドラーを提供します。
拡張:GenericAPIView、ListModelMixin
RetrieveAPIView
**単一のモデルインスタンス**を表す**読み取り専用**エンドポイントに使用されます。
get
メソッドハンドラーを提供します。
拡張:GenericAPIView、RetrieveModelMixin
DestroyAPIView
**単一のモデルインスタンス**の**削除専用**エンドポイントに使用されます。
delete
メソッドハンドラーを提供します。
拡張:GenericAPIView、DestroyModelMixin
UpdateAPIView
**単一のモデルインスタンス**の**更新専用**エンドポイントに使用されます。
put
およびpatch
メソッドハンドラーを提供します。
拡張:GenericAPIView、UpdateModelMixin
ListCreateAPIView
**モデルインスタンスのコレクション**を表す**読み取り/書き込み**エンドポイントに使用されます。
get
およびpost
メソッドハンドラーを提供します。
拡張:GenericAPIView、ListModelMixin、CreateModelMixin
RetrieveUpdateAPIView
**単一のモデルインスタンス**を表す**読み取りまたは更新**エンドポイントに使用されます。
get
、put
、およびpatch
メソッドハンドラーを提供します。
拡張:GenericAPIView、RetrieveModelMixin、UpdateModelMixin
RetrieveDestroyAPIView
**単一のモデルインスタンス**を表す**読み取りまたは削除**エンドポイントに使用されます。
get
およびdelete
メソッドハンドラーを提供します。
拡張:GenericAPIView、RetrieveModelMixin、DestroyModelMixin
RetrieveUpdateDestroyAPIView
**単一のモデルインスタンス**を表す**読み取り/書き込み/削除**エンドポイントに使用されます。
get
、put
、patch
、およびdelete
メソッドハンドラーを提供します。
拡張:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin
汎用ビューのカスタマイズ
多くの場合、既存の汎用ビューを使用しますが、わずかにカスタマイズされた動作を使用します。複数の場所でカスタマイズされた動作の一部を再利用している場合は、その動作を共通クラスにリファクタリングして、必要なビューまたはビューセットに適用することができます。
カスタム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)を提供します。