diff options
Diffstat (limited to 'docs/tutorial/6-viewsets-and-routers.md')
| -rw-r--r-- | docs/tutorial/6-viewsets-and-routers.md | 40 | 
1 files changed, 22 insertions, 18 deletions
| diff --git a/docs/tutorial/6-viewsets-and-routers.md b/docs/tutorial/6-viewsets-and-routers.md index f16add39..63dff73f 100644 --- a/docs/tutorial/6-viewsets-and-routers.md +++ b/docs/tutorial/6-viewsets-and-routers.md @@ -10,7 +10,7 @@ A `ViewSet` class is only bound to a set of method handlers at the last moment,  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 then with a single class: +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 @@ -21,11 +21,11 @@ First of all let's refactor our `UserList` and `UserDetail` views into a single          queryset = User.objects.all()          serializer_class = UserSerializer -Here we've used `ReadOnlyModelViewSet` class to automatically provide the default 'read-only' operations.  We're still setting the `queryset` and `serializer_class` attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes. +Here we've used the `ReadOnlyModelViewSet` class to automatically provide the default 'read-only' operations.  We're still setting the `queryset` and `serializer_class` attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes.  Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighlight` view classes.  We can remove the three views, and again replace them with a single class. -    from rest_framework.decorators import link +    from rest_framework.decorators import detail_route      class SnippetViewSet(viewsets.ModelViewSet):          """ @@ -39,19 +39,21 @@ Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighl          permission_classes = (permissions.IsAuthenticatedOrReadOnly,                                IsOwnerOrReadOnly,) -        @link(renderer_classes=[renderers.StaticHTMLRenderer]) +        @detail_route(renderer_classes=[renderers.StaticHTMLRenderer])          def highlight(self, request, *args, **kwargs):              snippet = self.get_object()              return Response(snippet.highlighted) -        def pre_save(self, obj): -            obj.owner = self.request.user +        def perform_create(self, serializer): +                serializer.save(owner=self.request.user)  This time we've used the `ModelViewSet` class in order to get the complete set of default read and write operations. -Notice that we've also used the `@link` decorator to create a custom action, named `highlight`.  This decorator can be used to add any custom endpoints that don't fit into the standard `create`/`update`/`delete` style. +Notice that we've also used the `@detail_route` decorator to create a custom action, named `highlight`.  This decorator can be used to add any custom endpoints that don't fit into the standard `create`/`update`/`delete` style. -Custom actions which use the `@link` decorator will respond to `GET` requests.  We could have instead used the `@action` decorator if we wanted an action that responded to `POST` requests. +Custom actions which use the `@detail_route` decorator will respond to `GET` requests.  We can use the `methods` argument if we wanted an action that responded to `POST` requests. + +The URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include url_path as a decorator keyword argument.  ## Binding ViewSets to URLs explicitly @@ -60,7 +62,8 @@ To see what's going on under the hood let's first explicitly create a set of vie  In the `urls.py` file we bind our `ViewSet` classes into a set of concrete views. -    from snippets.views import SnippetViewSet, UserViewSet +    from snippets.views import SnippetViewSet, UserViewSet, api_root +    from rest_framework import renderers      snippet_list = SnippetViewSet.as_view({          'get': 'list', @@ -84,16 +87,16 @@ In the `urls.py` file we bind our `ViewSet` classes into a set of concrete views  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, that we can register the views with the URL conf as usual. +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(patterns('snippets.views', -        url(r'^$', 'api_root'), +    urlpatterns = format_suffix_patterns([ +        url(r'^$', api_root),          url(r'^snippets/$', snippet_list, name='snippet-list'),          url(r'^snippets/(?P<pk>[0-9]+)/$', snippet_detail, name='snippet-detail'),          url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),          url(r'^users/$', user_list, name='user-list'),          url(r'^users/(?P<pk>[0-9]+)/$', user_detail, name='user-detail') -    )) +    ])  ## Using Routers @@ -101,6 +104,7 @@ Because we're using `ViewSet` classes rather than `View` classes, we actually do  Here's our re-wired `urls.py` file. +    from django.conf.urls import url, include      from snippets import views      from rest_framework.routers import DefaultRouter @@ -110,11 +114,11 @@ Here's our re-wired `urls.py` file.      router.register(r'users', views.UserViewSet)      # The API URLs are now determined automatically by the router. -    # Additionally, we include the login URLs for the browseable API. -    urlpatterns = patterns('', +    # Additionally, we include the login URLs for the browsable API. +    urlpatterns = [          url(r'^', include(router.urls)),          url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) -    ) +    ]  Registering the viewsets with the router is similar to providing a urlpattern.  We include two arguments - the URL prefix for the views, and the viewset itself. @@ -128,7 +132,7 @@ That doesn't mean it's always the right approach to take.  There's a similar set  ## Reviewing our work -With an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browseable, and comes complete with authentication, per-object permissions, and multiple renderer formats. +With an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browsable, and comes complete with authentication, per-object permissions, and multiple renderer formats.  We've walked through each step of the design process, and seen how if we need to customize anything we can gradually work our way down to simply using regular Django views. @@ -136,7 +140,7 @@ You can review the final [tutorial code][repo] on GitHub, or try out a live exam  ## Onwards and upwards -We've reached the end of our tutorial.  If you want to get more involved in the REST framework project, here's a few places you can start: +We've reached the end of our tutorial.  If you want to get more involved in the REST framework project, here are a few places you can start:  * Contribute on [GitHub][github] by reviewing and submitting issues, and making pull requests.  * Join the [REST framework discussion group][group], and help build the community. | 
