diff options
Diffstat (limited to 'api-guide/routers.html')
| -rw-r--r-- | api-guide/routers.html | 99 |
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> |
