2021年7月25日日曜日

【和訳】Django Rest Framework チュートリアル6:ビューセットとルーター

【和訳】Django Rest Framework クイックスタート

【和訳】Django Rest Framework チュートリアル1:シリアル化

【和訳】Django Rest Framework チュートリアル2:リクエストとレスポンス

【和訳】Django Rest Framework チュートリアル3:クラスベースのビュー

【和訳】Django Rest Framework チュートリアル4:認証とアクセス許可

【和訳】Django Rest Framework チュートリアル5:リレーションとハイパーリンクされたAPI

【和訳】Django Rest Framework チュートリアル6:ビューセットとルーター 


チュートリアル6:ビューセットとルーター

RESTフレームワークには、ViewSetsを処理するための抽象が含まれています。
これにより、開発者はAPIの状態と相互作用のモデリングに集中でき、一般的な規則に基づいて、URL構造を自動的に処理できます。

ViewSetクラスはViewクラスとほぼ同じであり、getputようなメソッドハンドラがなく、代わりにretrieveupdateような操作を提供します。

ありがちなのは、あなたのURL conf定義の複雑さを解消するRouterクラスを使い、ViewSetが一連のビューとしてインスタンス化される最後のタイミングで、ViewSetクラスは一連のメソッドハンドラに紐づけされるだけである。


ViewSetを使用するためのリファクタリング

現在複数あるビューを取得して、ビューセットにリファクタリングしてみましょう。

まずUserListUserDetailビューをUserViewSetとして、1まとめにリファクタリングしましょう。
2つのビューを削除して、1つのクラスに置き換えることができます。

from rest_framework import viewsets

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    このビューセットは、自動的に `list` と `retrieve` アクションを提供する。
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

ここでは、ReadOnlyModelViewSetクラスを使用して、デフォルトの「読み取り専用」操作を自動的に提供しています。
通常のビューを使用していたときの
querysetserializer_classとまったく同じように属性を設定していますが、2つの別々のクラス(UserListUserDetail)に同じ情報を提供する必要はありません。

次に、我々はSnippetListSnippetDetailSnippetHighlightビュークラスを交換していく。
3つのビューを削除して、再び1つのクラスに置き換えることができます。

from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import permissions

class SnippetViewSet(viewsets.ModelViewSet):
    """
    このViewSetは、自動的に、
    `list`, `create`, `retrieve`, `update`, `destroy`
    アクションを提供する。

    さらに、私たちは `highlight` アクションも提供する。
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly]

    @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

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

今回、デフォルトの読み取りおよび書き込み操作の完全なセットを取得するためにModelViewSetクラスを使用しました

@actionデコレータを使用してhighlightという名前のカスタムアクションを作成したことにも注意してください。
このデコレータは、標準のcreateupdate/deleteスタイルに適合しない、任意のカスタムエンドポイントを追加するために使用することができます

@actionデコレータを使用するカスタムアクションは、デフォルトでGETリクエストにレスポンスます。
POSTリクエストに
応答するアクションが必要な場合はmethods引数を使用できます。

デフォルトでは、カスタムアクションのURLはメソッド名自体に依存します。URLの作成方法を変更したい場合はデコレータのキーワード引数としてurl_path含めることができます。


ViewSetをURLに明示的にバインドする

ハンドラーメソッドは、URLConfを定義するときにのみアクションにバインドされます。内部で何が起こっているかを確認するために、最初にViewSetから一連のビューを明示的に作成しましょう。

このsnippets/urls.pyファイルでは、ViewSetクラスを一連の具体的なビューにバインドします。

from snippets.views import SnippetViewSet, UserViewSet, api_root
from rest_framework import renderers

snippet_list = SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
snippet_detail = SnippetViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})
snippet_highlight = SnippetViewSet.as_view({
    'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])
user_list = UserViewSet.as_view({
    'get': 'list'
})
user_detail = UserViewSet.as_view({
    'get': 'retrieve'
})

httpメソッドを各ビューに必要なアクションにバインドすることにより、各ViewSetクラスから複数のビューを作成していることに注目してください

リソースを具体的なビューにバインドしたので、通常どおりビューをURLconfに登録できます。

urlpatterns = format_suffix_patterns([
    path('', api_root),
    path('snippets/', snippet_list, name='snippet-list'),
    path('snippets/<int:pk>/', snippet_detail, name='snippet-detail'),
    path('snippets/<int:pk>/highlight/', snippet_highlight, name='snippet-highlight'),
    path('users/', user_list, name='user-list'),
    path('users/<int:pk>/', user_detail, name='user-detail')
])


ルーターの使用

ViewラスではなくViewSetラスを使用しているため、私たちは自分で実際にURLconfを設計する必要はありません。

リソースをビューとURLに接続するための規則は、Routerクラスを使用して自動的に処理できます
適切なビューセットをルーターに登録し、残りはルーターに任せるだけです。

これが再配線されたsnippets/urls.pyファイルです。

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views

# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)

# The API URLs are now determined automatically by the router.
urlpatterns = [
    path('', include(router.urls)),
]

ビューセットをルーターに登録することは、urlpatternを提供することに似ています。
ビューのURLプレフィックスとビューセット自体の2つの引数が含まれています。

使用しているDefaultRouterクラスは、APIルートビューも自動的に作成するためapi_rootviewsモジュールからメソッドを削除できます


ビューとビューセット間のトレードオフ

ビューセットの使用は、非常に便利な抽象化になります。
これにより、URL規則がAPI全体で一貫していることを確認し、記述する必要のあるコードの量を最小限に抑え、URL confの詳細ではなく、APIが提供する相互作用と表現に集中できます。

それが常に正しいアプローチであるという意味ではありません。
関数ベースのビューの代わりにクラスベースのビューを使用する場合と同様に、考慮すべきトレードオフのセットがあります。
ビューセットの使用は、ビューを個別に作成するよりも明確ではありません。

0 件のコメント:

コメントを投稿

【和訳】Django Rest Framework 目次

目次 【和訳】Django Rest Framework クイックスタート 【和訳】Django Rest Framework チュートリアル1:シリアル化 【和訳】Django Rest Framework チュートリアル2:リクエストとレスポンス 【和訳】Django Res...