aboutsummaryrefslogtreecommitdiffstats
path: root/api-guide/routers.html
diff options
context:
space:
mode:
Diffstat (limited to 'api-guide/routers.html')
-rw-r--r--api-guide/routers.html99
1 files changed, 79 insertions, 20 deletions
diff --git a/api-guide/routers.html b/api-guide/routers.html
index 70dd61c4..77c6e585 100644
--- a/api-guide/routers.html
+++ b/api-guide/routers.html
@@ -190,6 +190,7 @@ a.fusion-poweredby {
<li><a href="#simplerouter">SimpleRouter</a></li>
<li><a href="#defaultrouter">DefaultRouter</a></li>
<li class="main"><a href="#custom-routers">Custom Routers</a></li>
+<li><a href="#customizing-dynamic-routes">Customizing dynamic routes</a></li>
<li><a href="#example">Example</a></li>
<li><a href="#advanced-custom-routers">Advanced custom routers</a></li>
<li class="main"><a href="#third-party-packages">Third Party Packages</a></li>
@@ -247,32 +248,36 @@ urlpatterns = router.urls
<p>This means you'll need to explicitly set the <code>base_name</code> argument when registering the viewset, as it could not be automatically determined from the model name.</p>
<hr />
<h3 id="extra-link-and-actions">Extra link and actions</h3>
-<p>Any methods on the viewset decorated with <code>@link</code> or <code>@action</code> will also be routed.
+<p>Any methods on the viewset decorated with <code>@detail_route</code> or <code>@list_route</code> will also be routed.
For example, given a method like this on the <code>UserViewSet</code> class:</p>
<pre class="prettyprint lang-py"><code>from myapp.permissions import IsAdminOrIsSelf
-from rest_framework.decorators import action
+from rest_framework.decorators import detail_route
-@action(permission_classes=[IsAdminOrIsSelf])
-def set_password(self, request, pk=None):
+class UserViewSet(ModelViewSet):
...
+
+ @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
+ def set_password(self, request, pk=None):
+ ...
</code></pre>
<p>The following URL pattern would additionally be generated:</p>
<ul>
<li>URL pattern: <code>^users/{pk}/set_password/$</code> Name: <code>'user-set-password'</code></li>
</ul>
+<p>For more information see the viewset documentation on <a href="viewsets.html#marking-extra-actions-for-routing">marking extra actions for routing</a>.</p>
<h1 id="api-guide">API Guide</h1>
<h2 id="simplerouter">SimpleRouter</h2>
-<p>This router includes routes for the standard set of <code>list</code>, <code>create</code>, <code>retrieve</code>, <code>update</code>, <code>partial_update</code> and <code>destroy</code> actions. The viewset can also mark additional methods to be routed, using the <code>@link</code> or <code>@action</code> decorators.</p>
+<p>This router includes routes for the standard set of <code>list</code>, <code>create</code>, <code>retrieve</code>, <code>update</code>, <code>partial_update</code> and <code>destroy</code> actions. The viewset can also mark additional methods to be routed, using the <code>@detail_route</code> or <code>@list_route</code> decorators.</p>
<table border=1>
<tr><th>URL Style</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr>
<tr><td rowspan=2>{prefix}/</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>
<tr><td>POST</td><td>create</td></tr>
+ <tr><td>{prefix}/{methodname}/</td><td>GET, or as specified by `methods` argument</td><td>`@list_route` decorated method</td><td>{basename}-{methodname}</td></tr>
<tr><td rowspan=4>{prefix}/{lookup}/</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>
<tr><td>PUT</td><td>update</td></tr>
<tr><td>PATCH</td><td>partial_update</td></tr>
<tr><td>DELETE</td><td>destroy</td></tr>
- <tr><td rowspan=2>{prefix}/{lookup}/{methodname}/</td><td>GET</td><td>@link decorated method</td><td rowspan=2>{basename}-{methodname}</td></tr>
- <tr><td>POST</td><td>@action decorated method</td></tr>
+ <tr><td>{prefix}/{lookup}/{methodname}/</td><td>GET, or as specified by `methods` argument</td><td>`@detail_route` decorated method</td><td>{basename}-{methodname}</td></tr>
</table>
<p>By default the URLs created by <code>SimpleRouter</code> are appended with a trailing slash.
@@ -280,6 +285,11 @@ This behavior can be modified by setting the <code>trailing_slash</code> argumen
<pre class="prettyprint lang-py"><code>router = SimpleRouter(trailing_slash=False)
</code></pre>
<p>Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style.</p>
+<p>The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the <code>lookup_value_regex</code> attribute on the viewset. For example, you can limit the lookup to valid UUIDs:</p>
+<pre class="prettyprint lang-py"><code>class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
+ lookup_field = 'my_model_id'
+ lookup_value_regex = '[0-9a-f]{32}'
+</code></pre>
<h2 id="defaultrouter">DefaultRouter</h2>
<p>This router is similar to <code>SimpleRouter</code> as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional <code>.json</code> style format suffixes.</p>
<table border=1>
@@ -287,12 +297,12 @@ This behavior can be modified by setting the <code>trailing_slash</code> argumen
<tr><td>[.format]</td><td>GET</td><td>automatically generated root view</td><td>api-root</td></tr></tr>
<tr><td rowspan=2>{prefix}/[.format]</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>
<tr><td>POST</td><td>create</td></tr>
+ <tr><td>{prefix}/{methodname}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@list_route` decorated method</td><td>{basename}-{methodname}</td></tr>
<tr><td rowspan=4>{prefix}/{lookup}/[.format]</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>
<tr><td>PUT</td><td>update</td></tr>
<tr><td>PATCH</td><td>partial_update</td></tr>
<tr><td>DELETE</td><td>destroy</td></tr>
- <tr><td rowspan=2>{prefix}/{lookup}/{methodname}/[.format]</td><td>GET</td><td>@link decorated method</td><td rowspan=2>{basename}-{methodname}</td></tr>
- <tr><td>POST</td><td>@action decorated method</td></tr>
+ <tr><td>{prefix}/{lookup}/{methodname}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@detail_route` decorated method</td><td>{basename}-{methodname}</td></tr>
</table>
<p>As with <code>SimpleRouter</code> the trailing slashes on the URL routes can be removed by setting the <code>trailing_slash</code> argument to <code>False</code> when instantiating the router.</p>
@@ -314,26 +324,75 @@ This behavior can be modified by setting the <code>trailing_slash</code> argumen
<li><code>{basename}</code> - The base to use for the URL names that are created.</li>
</ul>
<p><strong>initkwargs</strong>: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the <code>suffix</code> argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links.</p>
+<h2 id="customizing-dynamic-routes">Customizing dynamic routes</h2>
+<p>You can also customize how the <code>@list_route</code> and <code>@detail_route</code> decorators are routed.
+To route either or both of these decorators, include a <code>DynamicListRoute</code> and/or <code>DynamicDetailRoute</code> named tuple in the <code>.routes</code> list.</p>
+<p>The arguments to <code>DynamicListRoute</code> and <code>DynamicDetailRoute</code> are:</p>
+<p><strong>url</strong>: A string representing the URL to be routed. May include the same format strings as <code>Route</code>, and additionally accepts the <code>{methodname}</code> and <code>{methodnamehyphen}</code> format strings.</p>
+<p><strong>name</strong>: The name of the URL as used in <code>reverse</code> calls. May include the following format strings: <code>{basename}</code>, <code>{methodname}</code> and <code>{methodnamehyphen}</code>.</p>
+<p><strong>initkwargs</strong>: A dictionary of any additional arguments that should be passed when instantiating the view.</p>
<h2 id="example">Example</h2>
<p>The following example will only route to the <code>list</code> and <code>retrieve</code> actions, and does not use the trailing slash convention.</p>
-<pre class="prettyprint lang-py"><code>from rest_framework.routers import Route, SimpleRouter
+<pre class="prettyprint lang-py"><code>from rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter
-class ReadOnlyRouter(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',
- initkwargs={'suffix': 'List'}),
- Route(url=r'^{prefix}/{lookup}$',
- mapping={'get': 'retrieve'},
- name='{basename}-detail',
- initkwargs={'suffix': 'Detail'})
+ Route(
+ url=r'^{prefix}$',
+ mapping={'get': 'list'},
+ name='{basename}-list',
+ initkwargs={'suffix': 'List'}
+ ),
+ Route(
+ url=r'^{prefix}/{lookup}$',
+ mapping={'get': 'retrieve'},
+ name='{basename}-detail',
+ initkwargs={'suffix': 'Detail'}
+ ),
+ DynamicDetailRoute(
+ url=r'^{prefix}/{lookup}/{methodnamehyphen}$',
+ name='{basename}-{methodnamehyphen}',
+ initkwargs={}
+ )
]
</code></pre>
-<p>The <code>SimpleRouter</code> class provides another example of setting the <code>.routes</code> attribute.</p>
+<p>Let's take a look at the routes our <code>CustomReadOnlyRouter</code> would generate for a simple viewset.</p>
+<p><code>views.py</code>:</p>
+<pre class="prettyprint lang-py"><code>class UserViewSet(viewsets.ReadOnlyModelViewSet):
+ """
+ A viewset that provides the standard actions
+ """
+ queryset = User.objects.all()
+ serializer_class = UserSerializer
+ lookup_field = 'username'
+
+ @detail_route()
+ def group_names(self, request):
+ """
+ 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])
+</code></pre>
+<p><code>urls.py</code>:</p>
+<pre class="prettyprint lang-py"><code>router = CustomReadOnlyRouter()
+router.register('users', UserViewSet)
+urlpatterns = router.urls
+</code></pre>
+<p>The following mappings would be generated...</p>
+<table border=1>
+ <tr><th>URL</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr>
+ <tr><td>/users</td><td>GET</td><td>list</td><td>user-list</td></tr>
+ <tr><td>/users/{username}</td><td>GET</td><td>retrieve</td><td>user-detail</td></tr>
+ <tr><td>/users/{username}/group-names</td><td>GET</td><td>group_names</td><td>user-group-names</td></tr>
+</table>
+
+<p>For another example of setting the <code>.routes</code> attribute, see the source code for the <code>SimpleRouter</code> class.</p>
<h2 id="advanced-custom-routers">Advanced custom routers</h2>
<p>If you want to provide totally custom behavior, you can override <code>BaseRouter</code> and override the <code>get_urls(self)</code> method. The method should inspect the registered viewsets and return a list of URL patterns. The registered prefix, viewset and basename tuples may be inspected by accessing the <code>self.registry</code> attribute. </p>
<p>You may also want to override the <code>get_default_base_name(self, viewset)</code> method, or else always explicitly set the <code>base_name</code> argument when registering your viewsets with the router.</p>