mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-02 20:54:42 +03:00
Tweaks
This commit is contained in:
parent
fd3f538e9f
commit
371698331c
|
@ -208,14 +208,14 @@ Should be mixed in with [SingleObjectAPIView].
|
|||
|
||||
Provides a `.update(request, *args, **kwargs)` method, that implements updating and saving an existing model instance.
|
||||
|
||||
Also provides a `.partial_update(request, *args, **kwargs)` method, which is similar to the `update` method, except that all fields for the update will be optional. This allows support for HTTP `PATCH` requests.
|
||||
|
||||
If an object is updated this returns a `200 OK` response, with a serialized representation of the object as the body of the response.
|
||||
|
||||
If an object is created, for example when making a `DELETE` request followed by a `PUT` request to the same URL, this returns a `201 Created` response, with a serialized representation of the object as the body of the response.
|
||||
|
||||
If the request data provided for updating the object was invalid, a `400 Bad Request` response will be returned, with the error details as the body of the response.
|
||||
|
||||
A boolean `partial` keyword argument may be supplied to the `.update()` method. If `partial` is set to `True`, all fields for the update will be optional. This allows support for HTTP `PATCH` requests.
|
||||
|
||||
Should be mixed in with [SingleObjectAPIView].
|
||||
|
||||
## DestroyModelMixin
|
||||
|
|
|
@ -19,6 +19,8 @@ First of all let's refactor our `UserListView` and `UserDetailView` views into a
|
|||
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 seperate 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 import viewsets
|
||||
|
@ -29,8 +31,7 @@ Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighl
|
|||
This viewset automatically provides `list`, `create`, `retrieve`,
|
||||
`update` and `destroy` actions.
|
||||
|
||||
Additionally we provide an extra `highlight` action, by using the
|
||||
`@link` decorator.
|
||||
Additionally we also provide an extra `highlight` action.
|
||||
"""
|
||||
queryset = Snippet.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
|
@ -45,25 +46,40 @@ Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighl
|
|||
def pre_save(self, obj):
|
||||
obj.owner = self.request.user
|
||||
|
||||
Notice that we've used the `@link` decorator for the `highlight` method.
|
||||
This decorator can be used to add custom endpoints, other than the standard `create`/`update`/`delete` endpoints.
|
||||
This time we've used the `ModelViewSet` class in order to get the complete set of default read and write operations.
|
||||
|
||||
The `@link` decorator will
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
## Binding ViewSets to URLs explicitly
|
||||
|
||||
The handler methods only get bound to the actions when we define the URLConf.
|
||||
To see what's going on under the hood let's first explicitly create a set of views from our ViewSets.
|
||||
|
||||
In the `urls.py` file we first need to bind our `ViewSet` classes into a set of concrete views.
|
||||
In the `urls.py` file we bind our `ViewSet` classes into a set of concrete views.
|
||||
|
||||
from snippets.resources import SnippetResource, UserResource
|
||||
|
||||
snippet_list = SnippetViewSet.as_view({'get': 'list', 'post': 'create'})
|
||||
snippet_detail = SnippetViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})
|
||||
snippet_highlight = SnippetViewSet.as_view({'get': 'highlight'})
|
||||
user_list = UserViewSet.as_view({'get': 'list', 'post': 'create'})
|
||||
user_detail = UserViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})
|
||||
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'
|
||||
})
|
||||
user_list = UserViewSet.as_view({
|
||||
'get': 'list'
|
||||
})
|
||||
user_detail = UserViewSet.as_view({
|
||||
'get': 'retrieve'
|
||||
})
|
||||
|
||||
Notice how we're creating multiple views from each `ViewSet` class, by binding the http methods to the required action for each view.
|
||||
|
||||
|
@ -80,7 +96,7 @@ Now that we've bound our resources into concrete views, that we can register the
|
|||
|
||||
## Using Routers
|
||||
|
||||
Now that we're using `ViewSet` classes rather than `View` classes, we actually don't need to design the URL conf ourselves. The conventions for wiring up resources into views and urls can be handled automatically, using a `Router` class. All we need to do is register the appropriate view sets with a router, and let it do the rest.
|
||||
Because we're using `ViewSet` classes rather than `View` classes, we actually don't need to design the URL conf ourselves. The conventions for wiring up resources into views and urls can be handled automatically, using a `Router` class. All we need to do is register the appropriate view sets with a router, and let it do the rest.
|
||||
|
||||
Here's our re-wired `urls.py` file.
|
||||
|
||||
|
@ -89,14 +105,14 @@ Here's our re-wired `urls.py` file.
|
|||
|
||||
# Create a router and register our views and view sets with it.
|
||||
router = DefaultRouter()
|
||||
router.register(r'^/', views.api_root)
|
||||
router.register(r'^/$', views.api_root)
|
||||
router.register(r'^snippets/', views.SnippetViewSet, 'snippet')
|
||||
router.register(r'^users/', views.UserViewSet, 'user')
|
||||
|
||||
# The urlconf is determined automatically by the router.
|
||||
urlpatterns = router.urlpatterns
|
||||
|
||||
# Add format suffixes to all our URL patterns.
|
||||
# We can still add format suffixes to all our URL patterns.
|
||||
urlpatterns = format_suffix_patterns(urlpatterns)
|
||||
|
||||
## Trade-offs between views vs viewsets.
|
||||
|
|
|
@ -187,8 +187,7 @@ class UpdateAPIView(mixins.UpdateModelMixin,
|
|||
return self.update(request, *args, **kwargs)
|
||||
|
||||
def patch(self, request, *args, **kwargs):
|
||||
kwargs['partial'] = True
|
||||
return self.update(request, *args, **kwargs)
|
||||
return self.partial_update(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ListCreateAPIView(mixins.ListModelMixin,
|
||||
|
@ -217,8 +216,7 @@ class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
|
|||
return self.update(request, *args, **kwargs)
|
||||
|
||||
def patch(self, request, *args, **kwargs):
|
||||
kwargs['partial'] = True
|
||||
return self.update(request, *args, **kwargs)
|
||||
return self.partial_update(request, *args, **kwargs)
|
||||
|
||||
|
||||
class RetrieveDestroyAPIView(mixins.RetrieveModelMixin,
|
||||
|
@ -248,8 +246,7 @@ class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
|
|||
return self.update(request, *args, **kwargs)
|
||||
|
||||
def patch(self, request, *args, **kwargs):
|
||||
kwargs['partial'] = True
|
||||
return self.update(request, *args, **kwargs)
|
||||
return self.partial_update(request, *args, **kwargs)
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
return self.destroy(request, *args, **kwargs)
|
||||
|
|
|
@ -137,6 +137,10 @@ class UpdateModelMixin(object):
|
|||
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
kwargs['partial'] = True
|
||||
return self.update(request, *args, **kwargs)
|
||||
|
||||
def pre_save(self, obj):
|
||||
"""
|
||||
Set any attributes on the object that are implicit in the request.
|
||||
|
|
|
@ -20,8 +20,16 @@ class BaseRouter(object):
|
|||
|
||||
class DefaultRouter(BaseRouter):
|
||||
route_list = [
|
||||
(r'$', {'get': 'list', 'post': 'create'}, 'list'),
|
||||
(r'(?P<pk>[^/]+)/$', {'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}, 'detail'),
|
||||
(r'$', {
|
||||
'get': 'list',
|
||||
'post': 'create'
|
||||
}, 'list'),
|
||||
(r'(?P<pk>[^/]+)/$', {
|
||||
'get': 'retrieve',
|
||||
'put': 'update',
|
||||
'patch': 'partial_update',
|
||||
'delete': 'destroy'
|
||||
}, 'detail'),
|
||||
]
|
||||
extra_routes = r'(?P<pk>[^/]+)/%s/$'
|
||||
name_format = '%s-%s'
|
||||
|
|
Loading…
Reference in New Issue
Block a user