mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-09 08:00:52 +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.
|
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 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 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.
|
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].
|
Should be mixed in with [SingleObjectAPIView].
|
||||||
|
|
||||||
## DestroyModelMixin
|
## DestroyModelMixin
|
||||||
|
|
|
@ -19,6 +19,8 @@ First of all let's refactor our `UserListView` and `UserDetailView` views into a
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
serializer_class = UserSerializer
|
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.
|
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
|
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`,
|
This viewset automatically provides `list`, `create`, `retrieve`,
|
||||||
`update` and `destroy` actions.
|
`update` and `destroy` actions.
|
||||||
|
|
||||||
Additionally we provide an extra `highlight` action, by using the
|
Additionally we also provide an extra `highlight` action.
|
||||||
`@link` decorator.
|
|
||||||
"""
|
"""
|
||||||
queryset = Snippet.objects.all()
|
queryset = Snippet.objects.all()
|
||||||
serializer_class = SnippetSerializer
|
serializer_class = SnippetSerializer
|
||||||
|
@ -45,25 +46,40 @@ Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighl
|
||||||
def pre_save(self, obj):
|
def pre_save(self, obj):
|
||||||
obj.owner = self.request.user
|
obj.owner = self.request.user
|
||||||
|
|
||||||
Notice that we've used the `@link` decorator for the `highlight` method.
|
This time we've used the `ModelViewSet` class in order to get the complete set of default read and write operations.
|
||||||
This decorator can be used to add custom endpoints, other than the standard `create`/`update`/`delete` endpoints.
|
|
||||||
|
|
||||||
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
|
## Binding ViewSets to URLs explicitly
|
||||||
|
|
||||||
The handler methods only get bound to the actions when we define the URLConf.
|
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.
|
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
|
from snippets.resources import SnippetResource, UserResource
|
||||||
|
|
||||||
snippet_list = SnippetViewSet.as_view({'get': 'list', 'post': 'create'})
|
snippet_list = SnippetViewSet.as_view({
|
||||||
snippet_detail = SnippetViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})
|
'get': 'list',
|
||||||
snippet_highlight = SnippetViewSet.as_view({'get': 'highlight'})
|
'post': 'create'
|
||||||
user_list = UserViewSet.as_view({'get': 'list', 'post': 'create'})
|
})
|
||||||
user_detail = UserViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})
|
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.
|
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
|
## 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.
|
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.
|
# Create a router and register our views and view sets with it.
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register(r'^/', views.api_root)
|
router.register(r'^/$', views.api_root)
|
||||||
router.register(r'^snippets/', views.SnippetViewSet, 'snippet')
|
router.register(r'^snippets/', views.SnippetViewSet, 'snippet')
|
||||||
router.register(r'^users/', views.UserViewSet, 'user')
|
router.register(r'^users/', views.UserViewSet, 'user')
|
||||||
|
|
||||||
# The urlconf is determined automatically by the router.
|
# The urlconf is determined automatically by the router.
|
||||||
urlpatterns = router.urlpatterns
|
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)
|
urlpatterns = format_suffix_patterns(urlpatterns)
|
||||||
|
|
||||||
## Trade-offs between views vs viewsets.
|
## Trade-offs between views vs viewsets.
|
||||||
|
|
|
@ -187,8 +187,7 @@ class UpdateAPIView(mixins.UpdateModelMixin,
|
||||||
return self.update(request, *args, **kwargs)
|
return self.update(request, *args, **kwargs)
|
||||||
|
|
||||||
def patch(self, request, *args, **kwargs):
|
def patch(self, request, *args, **kwargs):
|
||||||
kwargs['partial'] = True
|
return self.partial_update(request, *args, **kwargs)
|
||||||
return self.update(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ListCreateAPIView(mixins.ListModelMixin,
|
class ListCreateAPIView(mixins.ListModelMixin,
|
||||||
|
@ -217,8 +216,7 @@ class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
|
||||||
return self.update(request, *args, **kwargs)
|
return self.update(request, *args, **kwargs)
|
||||||
|
|
||||||
def patch(self, request, *args, **kwargs):
|
def patch(self, request, *args, **kwargs):
|
||||||
kwargs['partial'] = True
|
return self.partial_update(request, *args, **kwargs)
|
||||||
return self.update(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RetrieveDestroyAPIView(mixins.RetrieveModelMixin,
|
class RetrieveDestroyAPIView(mixins.RetrieveModelMixin,
|
||||||
|
@ -248,8 +246,7 @@ class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
|
||||||
return self.update(request, *args, **kwargs)
|
return self.update(request, *args, **kwargs)
|
||||||
|
|
||||||
def patch(self, request, *args, **kwargs):
|
def patch(self, request, *args, **kwargs):
|
||||||
kwargs['partial'] = True
|
return self.partial_update(request, *args, **kwargs)
|
||||||
return self.update(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, *args, **kwargs):
|
||||||
return self.destroy(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)
|
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):
|
def pre_save(self, obj):
|
||||||
"""
|
"""
|
||||||
Set any attributes on the object that are implicit in the request.
|
Set any attributes on the object that are implicit in the request.
|
||||||
|
|
|
@ -20,8 +20,16 @@ class BaseRouter(object):
|
||||||
|
|
||||||
class DefaultRouter(BaseRouter):
|
class DefaultRouter(BaseRouter):
|
||||||
route_list = [
|
route_list = [
|
||||||
(r'$', {'get': 'list', 'post': 'create'}, 'list'),
|
(r'$', {
|
||||||
(r'(?P<pk>[^/]+)/$', {'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}, 'detail'),
|
'get': 'list',
|
||||||
|
'post': 'create'
|
||||||
|
}, 'list'),
|
||||||
|
(r'(?P<pk>[^/]+)/$', {
|
||||||
|
'get': 'retrieve',
|
||||||
|
'put': 'update',
|
||||||
|
'patch': 'partial_update',
|
||||||
|
'delete': 'destroy'
|
||||||
|
}, 'detail'),
|
||||||
]
|
]
|
||||||
extra_routes = r'(?P<pk>[^/]+)/%s/$'
|
extra_routes = r'(?P<pk>[^/]+)/%s/$'
|
||||||
name_format = '%s-%s'
|
name_format = '%s-%s'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user