目次
【和訳】Django Rest Framework クイックスタート
【和訳】Django Rest Framework チュートリアル1:シリアル化
【和訳】Django Rest Framework チュートリアル2:リクエストとレスポンス
【和訳】Django Rest Framework チュートリアル3:クラスベースのビュー
【和訳】Django Rest Framework チュートリアル4:認証とアクセス許可
Pythonの勉強メモとか
【和訳】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:ビューセットとルーター
RESTフレームワークには、ViewSets
を処理するための抽象が含まれています。
これにより、開発者はAPIの状態と相互作用のモデリングに集中でき、一般的な規則に基づいて、URL構造を自動的に処理できます。
ViewSet
クラスはView
クラスとほぼ同じであり、get
かput
ようなメソッドハンドラがなく、代わりにretrieve
やupdate
のような操作を提供します。
ありがちなのは、あなたのURL conf定義の複雑さを解消するRouter
クラスを使い、ViewSet
が一連のビューとしてインスタンス化される最後のタイミングで、ViewSetクラスは一連のメソッドハンドラに紐づけされるだけである。
現在複数あるビューを取得して、ビューセットにリファクタリングしてみましょう。
まずUserList
とUserDetail
ビューをUserViewSet
として、1まとめにリファクタリングしましょう。
2つのビューを削除して、1つのクラスに置き換えることができます。
from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
このビューセットは、自動的に `list` と `retrieve` アクションを提供する。
"""
queryset = User.objects.all()
serializer_class = UserSerializer
ここでは、ReadOnlyModelViewSet
クラスを使用して、デフォルトの「読み取り専用」操作を自動的に提供しています。
通常のビューを使用していたときのqueryset
とserializer_class
とまったく同じように属性を設定していますが、2つの別々のクラス(UserList
とUserDetail
)に同じ情報を提供する必要はありません。
次に、我々はSnippetList
とSnippetDetail
とSnippetHighlight
ビュークラスを交換していく。
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
という名前のカスタムアクションを作成したことにも注意してください。
このデコレータは、標準のcreate
/ update
/delete
スタイルに適合しない、任意のカスタムエンドポイントを追加するために使用することができます。
@action
デコレータを使用するカスタムアクションは、デフォルトでGET
リクエストにレスポンスします。POST
リクエストに応答するアクションが必要な場合は、methods
引数を使用できます。
デフォルトでは、カスタムアクションのURLはメソッド名自体に依存します。URLの作成方法を変更したい場合はデコレータのキーワード引数としてurl_path
を含めることができます。
ハンドラーメソッドは、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_root
、views
モジュールからメソッドを削除できます。
ビューセットの使用は、非常に便利な抽象化になります。
これにより、URL規則がAPI全体で一貫していることを確認し、記述する必要のあるコードの量を最小限に抑え、URL confの詳細ではなく、APIが提供する相互作用と表現に集中できます。
それが常に正しいアプローチであるという意味ではありません。
関数ベースのビューの代わりにクラスベースのビューを使用する場合と同様に、考慮すべきトレードオフのセットがあります。
ビューセットの使用は、ビューを個別に作成するよりも明確ではありません。
【和訳】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:ビューセットとルーター
現在、API内のリレーションは、主キーを使用して表されています。
チュートリアルのこのページでは、リレーションを表すために、主キーの代わりにハイパーリンクを使用することで、APIの凝集度と発見可能性を向上させます。
現在、「スニペット」と「ユーザー」のエンドポイントがありますが、APIへの単一のエントリポイントはありません。
これを作成するには、通常の関数ベースのビューと、前に紹介した@api_view
デコレータを使用します。snippets/views.py
に追加します:
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
@api_view(['GET'])
def api_root(request, format=None):
return Response({
'users': reverse('user-list', request=request, format=format),
'snippets': reverse('snippet-list', request=request, format=format)
})
ここで2つのことに注意する必要があります。
まず、完全修飾URLを返すためにRESTフレームワークのreverse
関数を使用しています。
次に、URLパターンは、後でsnippets/urls.py
内で宣言する便利な名前で識別されます。
明らかにコードスニペットAPIに欠けている他の機能は、エンドポイントを強調表示するコードです。
他のすべてのAPIエンドポイントとは異なり、JSONは使用せず、代わりにHTML表現を使用したいです。
RESTフレームワークによって提供されるHTMLレンダラーには2つのスタイルがあります。
1つはテンプレートを使用してレンダリングされたHTMLを処理するためのもので、
もう1つは事前にレンダリングされたHTMLを処理するためのものです。
2番目のレンダラーは、今回、エンドポイントに使用したいレンダラーです。
コードハイライトビューを作成するときに考慮する必要があるもう1つのことは、使用できる既存の具体的な汎用ビューがないことです。
オブジェクトインスタンスではなく、オブジェクトインスタンスのプロパティを返したいのです。
具体的なジェネリックビューを使用する代わりに、インスタンスを表すために基底クラスを使用し、独自の.get()
メソッドを作成します。snippets/views.py
に追加します:
from rest_framework import renderers
from rest_framework.response import Response
class SnippetHighlight(generics.GenericAPIView):
queryset = Snippet.objects.all()
renderer_classes = [renderers.StaticHTMLRenderer]
def get(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
いつものように、作成した新しいビューをURLconfに追加する必要があります。snippets/urls.py
中の新しいAPIルートに、新しいURLパターンを追加します
path('', views.api_root),
次に、スニペットのハイライトのURLパターンを追加します。
path('snippets/<int:pk>/highlight/', views.SnippetHighlight.as_view()),
エンティティ間のリレーションを処理することは、WebAPI設計のより困難な側面の1つです。
リレーションを表すために選択できる方法はたくさんあります。
RESTフレームワークは、これらすべてのスタイルをサポートし、順方向または逆方向のリレーション全体に適用したり、汎用外部キーなどのカスタムマネージャー全体に適用したりできます。
ここでは、エンティティ間でハイパーリンクスタイルを使用します。そのために既存のModelSerializer
の代わりにHyperlinkedModelSerializer
を用いて、シリアライザーを拡張するように変更します
HyperlinkedModelSerializer
は、ModelSerializer
とは以下の点で異なります。
id
フィールドは含まれていません。HyperlinkedIdentityField
を使用して、url
フィールドが含まれますPrimaryKeyRelatedField
の代わりに、HyperlinkedRelatedField
を使用しますハイパーリンクを使用するように、既存のシリアライザーを簡単に書き直すことができます。snippets/serializers.py
に以下を追加します:
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
class Meta:
model = Snippet
fields = ['url', 'id', 'highlight', 'owner',
'title', 'code', 'linenos', 'language', 'style']
class UserSerializer(serializers.HyperlinkedModelSerializer):
snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)
class Meta:
model = User
fields = ['url', 'id', 'username', 'snippets']
新しい'highlight'
フィールドも追加したことに注意してください。
このフィールドは'snippet-highlight'
URLパターンを指し示すこと以外、(通常の)url
フィールドと同じ型であり、'snippet-detail'
の代わりです。
私たちのAPIには'.json'
などのフォーマット接尾語URLが使えるため、highlight
フィールド上で、highlight
フィールドが返すどの形式の接尾語付きハイパーリンクが'.html'
接尾語を使うべきかを指示する必要がある。
(※訳注:文法の解釈ミスがあるかも)
ハイパーリンクされたAPIを使用する場合は、URLパターンに名前を付ける必要があります。
名前を付ける必要のあるURLパターンを見てみましょう。
'user-list'
と'snippet-list'
を参照する。'snippet-highlight'
を参照するフィールドが含まれている。'snippet-detail'
を参照するフィールドが含まれている。'url'
フィールドが含まれており、デフォルトで'{model_name}-detail'
を参照する。今回は、'snippet-detail'
と'user-detail'
である。
これらすべての名前をURLconfに追加すると、最終的なsnippets/urls.py
ファイルは次のようになります。
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
# API endpoints
urlpatterns = format_suffix_patterns([
path('', views.api_root),
path('snippets/',
views.SnippetList.as_view(),
name='snippet-list'),
path('snippets/<int:pk>/',
views.SnippetDetail.as_view(),
name='snippet-detail'),
path('snippets/<int:pk>/highlight/',
views.SnippetHighlight.as_view(),
name='snippet-highlight'),
path('users/',
views.UserList.as_view(),
name='user-list'),
path('users/<int:pk>/',
views.UserDetail.as_view(),
name='user-detail')
])
ユーザーのリストビューとコードスニペットは、非常に多くのインスタンスを返す可能性があるため、結果をページ分割し、APIクライアントが個々のページをステップスルーできるようにする必要があります。
tutorial/settings.py
ファイルを少し変更することで、ページネーションを使用するように、デフォルトのリストスタイルを変更できます。次の設定を追加します。
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
RESTフレームワークの設定はすべて、REST_FRAMEWORK
という名前の単一のディクショナリ設定に名前空間が設定されていることに注意してください。
これにより、他のプロジェクト設定から十分に分離できます。
必要に応じてページネーションスタイルをカスタマイズすることもできますが、今回はデフォルトのままにします。
ブラウザを開いてブラウザから閲覧可能なAPIに移動すると、リンクをたどるだけの労力でAPIを巡回できることがわかります。
スニペットインスタンスの「ハイライト」リンクも表示され、ハイライトされたコードのHTML表現に移動します。
チュートリアルのパート6では、APIを構築するために必要なコードの量を減らすため、ビューセット(ViewSet)とルータ(Router)を使用する方法を見ていきます。
目次 【和訳】Django Rest Framework クイックスタート 【和訳】Django Rest Framework チュートリアル1:シリアル化 【和訳】Django Rest Framework チュートリアル2:リクエストとレスポンス 【和訳】Django Res...