MENU

rest_framwork チュートリアル⑥について

  • Python 3.11.4 / Django 4.2.4
目次

チュートリアル⑥:ViewSets & Routers

RESTフレームワークには、**ViewSets**という機能があり、これを使うと開発者はAPIの動きや役割に集中でき、URLの作成は簡単に自動で行われる。

**ViewSetクラスは、普通のViewクラスとよく似ているが、少し違うところがある。具体的には、getputという通常のメソッドの代わりに、情報を取得するretrieveや情報を更新するupdate**という操作が用意されている。

**ViewSetクラスは、特定の動作を行うための方法(メソッド)が、最後のステップで決まります。このステップは、URLの設定を簡単に作るRouter**クラスを使って行う。

  • Refactoring to use ViewSets Let’s take our current set of views, and refactor them into view sets. First of all let’s refactor our UserList and UserDetail views into a single UserViewSet. We can remove the two views, and replace them with a single class: from rest_framework import viewsets class UserViewSet(viewsets.ReadOnlyModelViewSet): """ This viewset automatically provides `list` and `retrieve` actions. """ queryset = User.objects.all() ここでは**ReadOnlyModelViewSetクラスを使用して、デフォルトの「読み取り専用」操作を自動的に提供している。通常のビューを使用していたときと同じようにquerysetserializer_class**の属性を設定しているが、もはや同じ情報を2つの異なるクラスに提供する必要はない。 (=通常のリストビューと詳細ビューを2つ使用する代わりに、1つのビューセットで両方の動作をカバーできるというDjango Rest Frameworkでのビューセットの利点) Next we’re going to replace the SnippetListSnippetDetail and SnippetHighlight view classes. We can remove the three views, and again replace them with a single class. from rest_framework.decorators import action from rest_framework.response import Response from rest_framework import permissions class SnippetViewSet(viewsets.ModelViewSet): """ This viewset automatically provides `list`, `create`, `retrieve`, `update` and `destroy` actions. Additionally we also provide an extra `highlight` action. """ 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という名前のカスタムアクションを作成したことにも注目!このデコレータは、標準的なcreate/update/deleteスタイルに合わないカスタムエンドポイントを追加するために使用することができる。 **@action**デコレータを使用するカスタムアクションは、デフォルトでGETリクエストに応答する。POSTリクエストに対応するアクションが欲しい場合は、methods引数を使用することができる。 カスタムアクションのURLは、デフォルトでメソッド名自体に依存する。URLの構築方法を変更したい場合は、デコレータのキーワード引数として**url_path**を含めることができる。
  • Binding ViewSets to URLs explicitly ハンドラーメソッドは、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' }) Notice how we’re creating multiple views from each ViewSet class, by binding the http methods to the required action for each view. Now that we’ve bound our resources into concrete views, we can register the views with the URL conf as usual. 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') ])
  • Using Routers Because we’re using ViewSet classes rather than View classes, we actually don’t need to design the URL conf ourselves. The conventions for wiring up resources into views and urls can be handled automatically, using a Router class. All we need to do is register the appropriate view sets with a router, and let it do the rest. Here’s our re-wired snippets/urls.py file. 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,basename="snippet") router.register(r'users', views.UserViewSet,basename="user") # The API URLs are now determined automatically by the router. urlpatterns = [ path('', include(router.urls)), ] ViewSetの登録は、urlpatternを提供するのと似ている。ビューのURLプレフィックスとViewSet自体の2つの引数を含める。 使用しているDefaultRouterクラスは、APIルートビューも自動的に作成するため、viewsモジュールからapi_rootメソッドを削除することができる。
  • Trade-offs between views vs viewsets ViewSetの使用は非常に便利な抽象化手段となることがある。これにより、API全体でのURLの規約が一貫性を持つことが保証され、必要なコードの量が最小限になり、URLの設定の詳細ではなく、APIが提供するインタラクションや表現に集中できる。 しかしそれが常に適切なアプローチであるとは限らない。クラスベースのビューを使用する代わりに関数ベースのビューを使用する場合と同様のトレードオフを考慮する必要がある。ViewSetを使用することは、ビューを個別に構築するよりも少しわかりにくい部分があることがある。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次