ルータ
リソースルーティングを使用すると、特定のリソースコントローラーのすべての共通ルートをすばやく宣言できます。 index ... のように個別のルートを宣言する代わりに、リソースルートは1行のコードでそれらを宣言します。
Railsなどの一部のWebフレームワークは、アプリケーションのURLを、受信リクエストを処理するロジックにどのようにマッピングするかを自動的に決定する機能を提供します。
REST frameworkは、Djangoに自動URLルーティングのサポートを追加し、ビューロジックを一連のURLに接続するためのシンプルで迅速かつ一貫性のある方法を提供します。
使用方法
SimpleRouter
を使用する簡単なURLconfの例を次に示します。
from rest_framework import routers
router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urls
register()
メソッドには2つの必須引数があります
prefix
- このルートセットに使用するURLプレフィックス。viewset
- ビューセットクラス。
必要に応じて、追加の引数を指定することもできます
basename
- 作成されるURL名に使用するベース。設定されていない場合、basenameは、viewsetのqueryset
属性に基づいて自動的に生成されます(存在する場合)。 viewsetにqueryset
属性が含まれていない場合は、viewsetを登録するときにbasename
を設定する必要があることに注意してください。
上記の例では、次のURLパターンが生成されます
- URLパターン:
^users/$
名前:'user-list'
- URLパターン:
^users/{pk}/$
名前:'user-detail'
- URLパターン:
^accounts/$
名前:'account-list'
- URLパターン:
^accounts/{pk}/$
名前:'account-detail'
注:basename
引数は、ビュー名パターンの最初の部分を指定するために使用されます。上記の例では、それはuser
またはaccount
部分です。
通常、basename
引数を指定する必要はありませんが、カスタムget_queryset
メソッドを定義したviewsetがある場合、viewsetに.queryset
属性が設定されていない可能性があります。そのviewsetを登録しようとすると、次のようなエラーが表示されます
'basename' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.
これは、モデル名から自動的に決定できなかったため、viewsetを登録するときにbasename
引数を明示的に設定する必要があることを意味します。
ルータでinclude
を使用する
ルータインスタンスの.urls
属性は、単なる標準のURLパターンのリストです。これらのURLを含める方法には、さまざまなスタイルがあります。
たとえば、既存のビューのリストにrouter.urls
を追加できます...
router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
]
urlpatterns += router.urls
または、Djangoのinclude
関数を使用することもできます...
urlpatterns = [
path('forgot-password', ForgotPasswordFormView.as_view()),
path('', include(router.urls)),
]
アプリケーション名前空間でinclude
を使用できます
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
path('api/', include((router.urls, 'app_name'))),
]
または、アプリケーションとインスタンスの両方の名前空間
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
]
詳細については、DjangoのURL名前空間のドキュメントとinclude
APIリファレンスを参照してください。
注:ハイパーリンクされたシリアライザで名前空間を使用する場合、シリアライザのview_name
パラメータが名前空間を正しく反映していることを確認する必要もあります。上記の例では、ユーザー詳細ビューにハイパーリンクされたシリアライザフィールドに、view_name='app_name:user-detail'
などのパラメータを含める必要があります。
自動view_name
生成では、%(model_name)-detail
のようなパターンが使用されます。モデル名が実際に競合しない限り、ハイパーリンクされたシリアライザを使用する場合は、Django REST Frameworkビューに名前空間を付けない方がよいでしょう。
追加アクションのルーティング
ビューセットは、メソッドを@action
デコレータで装飾することにより、ルーティングのための追加アクションをマークできます。これらの追加アクションは、生成されたルートに含まれます。たとえば、UserViewSet
クラスのset_password
メソッドが与えられた場合
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action
class UserViewSet(ModelViewSet):
...
@action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
...
次のルートが生成されます
- URLパターン:
^users/{pk}/set_password/$
- URL名:
'user-set-password'
デフォルトでは、URLパターンはメソッド名に基づいており、URL名はViewSet.basename
とハイフンで区切られたメソッド名の組み合わせです。これらの値のいずれかにデフォルトを使用しない場合は、代わりに@action
デコレータにurl_path
およびurl_name
引数を指定できます。
たとえば、カスタムアクションのURLを^users/{pk}/change-password/$
に変更する場合は、次のように記述できます
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action
class UserViewSet(ModelViewSet):
...
@action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
url_path='change-password', url_name='change_password')
def set_password(self, request, pk=None):
...
上記の例では、次のURLパターンが生成されるようになりました
- URLパス:
^users/{pk}/change-password/$
- URL名:
'user-change_password'
APIガイド
SimpleRouter
このルータには、list
、create
、retrieve
、update
、partial_update
、およびdestroy
アクションの標準セットのルートが含まれています。ビューセットは、@action
デコレータを使用して、ルーティングされる追加のメソッドをマークすることもできます。
URLスタイル | HTTPメソッド | アクション | URL名 |
---|---|---|---|
{prefix}/ | GET | list | {basename}-list |
POST | create | ||
{prefix}/{url_path}/ | GET、または `methods` 引数で指定されたメソッド | `@action(detail=False)` デコレータ付きメソッド | {basename}-{url_name} |
{prefix}/{lookup}/ | GET | GET | retrieve |
{basename}-detail | PUT | ||
update | PATCH | ||
partial_update | DELETE | ||
destroy | GET、または `methods` 引数で指定されたメソッド | {prefix}/{lookup}/{url_path}/ | {basename}-{url_name} |
{basename}-{url_name}
router = SimpleRouter(trailing_slash=False)
SimpleRouter
によって作成されたURLには、デフォルトで末尾にスラッシュが追加されます。この動作は、ルータをインスタンス化するときにtrailing_slash
引数をFalse
に設定することで変更できます。例えば
末尾のスラッシュはDjangoでは慣例ですが、Railsなどの一部の他のフレームワークではデフォルトでは使用されません。使用するスタイルの選択は、主に好みの問題ですが、一部のJavaScriptフレームワークは特定のルーティングスタイルを期待する場合があります。
router = SimpleRouter(use_regex_path=False)
デフォルトでは、SimpleRouter
によって作成された URL は正規表現を使用します。この動作は、ルータをインスタンス化するときに `use_regex_path` 引数を `False` に設定することで変更できます。この場合、パスコンバータ が使用されます。例えば
注:use_regex_path=False
は Django 2.x 以降でのみ機能します。この機能は 2.0.0 で導入されたためです。リリースノート を参照してください。
class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_id'
lookup_value_regex = '[0-9a-f]{32}'
class MyPathModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_uuid'
lookup_value_converter = 'uuid'
DefaultRouter
ルータは、スラッシュとピリオド文字以外の文字を含むルックアップ値に一致します。より制限的な(または寛大な)ルックアップパターンにするには、ビューセットに `lookup_value_regex` 属性を設定するか、パスコンバータを使用する場合は `lookup_value_converter` を設定します。たとえば、ルックアップを有効な UUID に制限できます
URLスタイル | HTTPメソッド | アクション | URL名 |
---|---|---|---|
このルータは上記のSimpleRouter に似ていますが、さらに、すべてのリストビューへのハイパーリンクを含むレスポンスを返すデフォルトのAPIルートビューが含まれています。また、オプションの.json スタイルのフォーマットサフィックスのルートも生成します。 | GET | [.format] | 自動生成されたルートビュー |
api-root | GET | list | {basename}-list |
POST | create | ||
上記と同じ | GET、または `methods` 引数で指定されたメソッド | `@action(detail=False)` デコレータ付きメソッド | {basename}-{url_name} |
上記と同じ | GET | GET | retrieve |
{basename}-detail | PUT | ||
update | PATCH | ||
partial_update | DELETE | ||
上記と同じ | GET、または `methods` 引数で指定されたメソッド | {prefix}/{lookup}/{url_path}/ | {basename}-{url_name} |
上記と同じ
router = DefaultRouter(trailing_slash=False)
カスタムルータ
SimpleRouter
と同様に、URLルートの末尾のスラッシュは、ルータをインスタンス化するときにtrailing_slash
引数をFalse
に設定することで削除できます。
カスタムルータを実装することは、それほど頻繁に行う必要のあることではありませんが、APIのURLの構造方法に関する特定の要件がある場合に役立ちます。これを行うことで、URL構造を再利用可能な方法でカプセル化できるため、新しいビューごとにURLパターンを明示的に記述する必要がなくなります。
カスタムルータを実装する最も簡単な方法は、既存のルータクラスの1つをサブクラス化することです。 .routes
属性は、各ビューセットにマッピングされるURLパターンのテンプレートに使用されます。 .routes
属性は、Route
という名前のタプルのリストです。
Route
という名前のタプルへの引数は次のとおりです
- url:ルーティングされるURLを表す文字列。次のフォーマット文字列を含めることができます
{prefix}
- このルートセットに使用するURLプレフィックス。{lookup}
- 単一のインスタンスとの照合に使用されるルックアップフィールド。
{trailing_slash}
- trailing_slash
引数に応じて '/' または空の文字列。
mapping:HTTPメソッド名からビューメソッドへのマッピング
{basename}
- 作成されるURL名に使用するベース。
initkwargs: ビューをインスタンス化する際に渡される追加の引数の辞書。detail
、basename
、suffix
引数は、ビューセットのイントロスペクション用に予約されており、ブラウザブルAPIによってビュー名とパンくずリストのリンクを生成するためにも使用されることに注意してください。
動的ルートのカスタマイズ
@action
デコレーターのルーティング方法をカスタマイズすることもできます。.routes
リストに DynamicRoute
名前付きタプルを含め、リストベースおよび詳細ベースのルートに適した detail
引数を設定します。detail
に加えて、DynamicRoute
の引数は以下のとおりです。
url: ルーティングされるURLを表す文字列。Route
と同じ形式の文字列を含めることができ、さらに {url_path}
形式の文字列も受け入れます。
name: reverse
呼び出しで使用されるURLの名前。次の形式の文字列を含めることができます。
{basename}
- 作成されるURL名に使用するベース。{url_name}
-@action
に提供されたurl_name
。
initkwargs: ビューをインスタンス化する際に渡される追加の引数の辞書。
例
次の例では、list
および retrieve
アクションへのみルーティングされ、末尾のスラッシュ規則は使用されません。
from rest_framework.routers import Route, DynamicRoute, SimpleRouter
class CustomReadOnlyRouter(SimpleRouter):
"""
A router for read-only APIs, which doesn't use trailing slashes.
"""
routes = [
Route(
url=r'^{prefix}$',
mapping={'get': 'list'},
name='{basename}-list',
detail=False,
initkwargs={'suffix': 'List'}
),
Route(
url=r'^{prefix}/{lookup}$',
mapping={'get': 'retrieve'},
name='{basename}-detail',
detail=True,
initkwargs={'suffix': 'Detail'}
),
DynamicRoute(
url=r'^{prefix}/{lookup}/{url_path}$',
name='{basename}-{url_name}',
detail=True,
initkwargs={}
)
]
簡単なビューセットに対して CustomReadOnlyRouter
が生成するルートを見てみましょう。
views.py
:
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_field = 'username'
@action(detail=True)
def group_names(self, request, pk=None):
"""
Returns a list of all the group names that the given
user belongs to.
"""
user = self.get_object()
groups = user.groups.all()
return Response([group.name for group in groups])
urls.py
:
router = CustomReadOnlyRouter()
router.register('users', UserViewSet)
urlpatterns = router.urls
以下のマッピングが生成されます...
URL | HTTPメソッド | アクション | URL名 |
---|---|---|---|
/users | GET | list | user-list |
/users/{username} | GET | GET | user-detail |
/users/{username}/group_names | GET | group_names | user-group-names |
.routes
属性の設定に関する別の例については、SimpleRouter
クラスのソースコードを参照してください。
高度なカスタムルータ
完全にカスタムの動作を提供する場合は、BaseRouter
をオーバーライドし、get_urls(self)
メソッドをオーバーライドできます。このメソッドは、登録されたビューセットを検査し、URLパターンのリストを返す必要があります。登録されたプレフィックス、ビューセット、および basename のタプルは、self.registry
属性にアクセスすることで検査できます。
get_default_basename(self, viewset)
メソッドをオーバーライドするか、ビューセットをルーターに登録する際に常に basename
引数を明示的に設定することもできます。
サードパーティパッケージ
以下のサードパーティパッケージも利用可能です。
DRFネストされたルータ
drf-nested-routers パッケージ は、ネストされたリソースを扱うためのルーターとリレーションシップフィールドを提供します。
ModelRouter (wq.db.rest)
wq.db パッケージ は、DefaultRouter
を register_model()
API で拡張した高度な ModelRouter クラス(およびシングルトンインスタンス)を提供します。 Django の admin.site.register
と同様に、rest.router.register_model
に必要な引数はモデルクラスだけです。URLプレフィックス、シリアライザー、およびビューセットの適切なデフォルトは、モデルとグローバル設定から推測されます。
from wq.db import rest
from myapp.models import MyModel
rest.router.register_model(MyModel)
DRF-extensions
DRF-extensions
パッケージ は、ネストされたビューセット、カスタマイズ可能なエンドポイント名 を持つ コレクションレベルのコントローラー を作成するための ルーター を提供します。