mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-31 07:57:55 +03:00 
			
		
		
		
	Add notes on 'method' argument to '@action' decorator
This commit is contained in:
		
						commit
						27d8b848bc
					
				|  | @ -126,6 +126,11 @@ The `@action` and `@link` decorators can additionally take extra arguments that | |||
|         def set_password(self, request, pk=None): | ||||
|            ... | ||||
| 
 | ||||
| The `@action` decorator will route `POST` requests by default, but may also accept other HTTP methods, by using the `method` argument.  For example: | ||||
| 
 | ||||
|         @action(methods=['POST', 'DELETE']) | ||||
|         def unset_password(self, request, pk=None): | ||||
|            ... | ||||
| --- | ||||
| 
 | ||||
| # API Reference | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ You can determine your currently installed version using `pip freeze`: | |||
| 
 | ||||
| * Added `get_url` hook to `HyperlinkedIdentityField`. | ||||
| * Serializer field `default` argument may be a callable. | ||||
| * `@action` decorator now accepts a `methods` argument. | ||||
| * Bugfix: The `lookup_field` option on `HyperlinkedIdentityField` should apply by default to the url field on the serializer. | ||||
| * Bugfix: `HyperlinkedIdentityField` should continue to support `pk_url_kwarg`, `slug_url_kwarg`, `slug_field`, in a pending deprecation state. | ||||
| * Bugfix: Ensure we always return 404 instead of 500 if a lookup field cannot be converted to the correct lookup type.  (Eg non-numeric `AutoInteger` pk lookup) | ||||
|  |  | |||
|  | @ -112,18 +112,18 @@ def link(**kwargs): | |||
|     Used to mark a method on a ViewSet that should be routed for GET requests. | ||||
|     """ | ||||
|     def decorator(func): | ||||
|         func.bind_to_method = 'get' | ||||
|         func.bind_to_methods = ['get'] | ||||
|         func.kwargs = kwargs | ||||
|         return func | ||||
|     return decorator | ||||
| 
 | ||||
| 
 | ||||
| def action(**kwargs): | ||||
| def action(methods=['post'], **kwargs): | ||||
|     """ | ||||
|     Used to mark a method on a ViewSet that should be routed for POST requests. | ||||
|     """ | ||||
|     def decorator(func): | ||||
|         func.bind_to_method = 'post' | ||||
|         func.bind_to_methods = methods | ||||
|         func.kwargs = kwargs | ||||
|         return func | ||||
|     return decorator | ||||
|  |  | |||
|  | @ -131,20 +131,20 @@ class SimpleRouter(BaseRouter): | |||
|         dynamic_routes = [] | ||||
|         for methodname in dir(viewset): | ||||
|             attr = getattr(viewset, methodname) | ||||
|             httpmethod = getattr(attr, 'bind_to_method', None) | ||||
|             if httpmethod: | ||||
|                 dynamic_routes.append((httpmethod, methodname)) | ||||
|             httpmethods = getattr(attr, 'bind_to_methods', None) | ||||
|             if httpmethods: | ||||
|                 dynamic_routes.append((httpmethods, methodname)) | ||||
| 
 | ||||
|         ret = [] | ||||
|         for route in self.routes: | ||||
|             if route.mapping == {'{httpmethod}': '{methodname}'}: | ||||
|                 # Dynamic routes (@link or @action decorator) | ||||
|                 for httpmethod, methodname in dynamic_routes: | ||||
|                 for httpmethods, methodname in dynamic_routes: | ||||
|                     initkwargs = route.initkwargs.copy() | ||||
|                     initkwargs.update(getattr(viewset, methodname).kwargs) | ||||
|                     ret.append(Route( | ||||
|                         url=replace_methodname(route.url, methodname), | ||||
|                         mapping={httpmethod: methodname}, | ||||
|                         mapping=dict((httpmethod, methodname) for httpmethod in httpmethods), | ||||
|                         name=replace_methodname(route.name, methodname), | ||||
|                         initkwargs=initkwargs, | ||||
|                     )) | ||||
|  |  | |||
|  | @ -25,6 +25,10 @@ class BasicViewSet(viewsets.ViewSet): | |||
|     def action2(self, request, *args, **kwargs): | ||||
|         return Response({'method': 'action2'}) | ||||
| 
 | ||||
|     @action(methods=['post', 'delete']) | ||||
|     def action3(self, request, *args, **kwargs): | ||||
|         return Response({'method': 'action2'}) | ||||
| 
 | ||||
|     @link() | ||||
|     def link1(self, request, *args, **kwargs): | ||||
|         return Response({'method': 'link1'}) | ||||
|  | @ -42,17 +46,20 @@ class TestSimpleRouter(TestCase): | |||
|         routes = self.router.get_routes(BasicViewSet) | ||||
|         decorator_routes = routes[2:] | ||||
|         # Make sure all these endpoints exist and none have been clobbered | ||||
|         for i, endpoint in enumerate(['action1', 'action2', 'link1', 'link2']): | ||||
|         for i, endpoint in enumerate(['action1', 'action2', 'action3', 'link1', 'link2']): | ||||
|             route = decorator_routes[i] | ||||
|             # check url listing | ||||
|             self.assertEqual(route.url, | ||||
|                              '^{{prefix}}/{{lookup}}/{0}/$'.format(endpoint)) | ||||
|             # check method to function mapping | ||||
|             if endpoint.startswith('action'): | ||||
|                 method_map = 'post' | ||||
|             if endpoint == 'action3': | ||||
|                 methods_map = ['post', 'delete'] | ||||
|             elif endpoint.startswith('action'): | ||||
|                 methods_map = ['post'] | ||||
|             else: | ||||
|                 method_map = 'get' | ||||
|             self.assertEqual(route.mapping[method_map], endpoint) | ||||
|                 methods_map = ['get'] | ||||
|             for method in methods_map: | ||||
|                 self.assertEqual(route.mapping[method], endpoint) | ||||
| 
 | ||||
| 
 | ||||
| class RouterTestModel(models.Model): | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user