8000 Add support for action and link routing · dhepper/django-rest-framework@fb41d2a · GitHub
[go: up one dir, main page]

Skip to content

Commit fb41d2a

Browse files
committed
Add support for action and link routing
1 parent c785628 commit fb41d2a

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

docs/tutorial/6-viewsets-and-routers.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,26 @@ Let's take our current set of views, and refactor them into view sets.
1212

1313
First of all let's refactor our `UserListView` and `UserDetailView` views into a single `UserViewSet`. We can remove the two views, and replace then with a single class:
1414

15-
class UserViewSet(viewsets.ModelViewSet):
15+
class UserViewSet(viewsets.ReadOnlyModelViewSet):
16+
"""
17+
This viewset automatically provides `list` and `detail` actions.
18+
"""
1619
queryset = User.objects.all()
1720
serializer_class = UserSerializer
1821

1922
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.
2023

24+
from rest_framework import viewsets
25+
from rest_framework.decorators import link
26+
2127
class SnippetViewSet(viewsets.ModelViewSet):
28+
"""
29+
This viewset automatically provides `list`, `create`, `retrieve`,
30+
`update` and `destroy` actions.
31+
32+
Additionally we provide an extra `highlight` action, by using the
33+
`@link` decorator.
34+
"""
2235
queryset = Snippet.objects.all()
2336
serializer_class = SnippetSerializer
2437
permission_classes = (permissions.IsAuthenticatedOrReadOnly,

rest_framework/decorators.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,25 @@ def decorator(func):
9797
func.permission_classes = permission_classes
9898
return func
9999
return decorator
100+
101+
102+
def link(**kwargs):
103+
"""
104+
Used to mark a method on a ViewSet that should be routed for GET requests.
105+
"""
106+
def decorator(func):
107+
func.bind_to_method = 'get'
108+
func.kwargs = kwargs
109+
return func
110+
return decorator
111+
112+
113+
def action(**kwargs):
114+
"""
115+
Used to mark a method on a ViewSet that should be routed for POST requests.
116+
"""
117+
def decorator(func):
118+
func.bind_to_method = 'post'
119+
func.kwargs = kwargs
120+
return func
121+
return decorator

rest_framework/routers.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ class DefaultRouter(BaseRouter):
2424
(r'$', {'get': 'list', 'post': 'create'}, '%s-list'),
2525
(r'(?P<pk>[^/]+)/$', {'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}, '%s-detail'),
2626
]
27+
extra_routes = (r'(?P<pk>[^/]+)/%s/$', '%s-%s')
2728

2829
def get_urlpatterns(self):
2930
ret = []
3031
for prefix, viewset, base_name in self.registry:
32+
# Bind standard routes
3133
for suffix, action_mapping, name_format in self.route_list:
3234

3335
# Only actions which actually exist on the viewset will be bound
@@ -36,8 +38,26 @@ def get_urlpatterns(self):
3638
if hasattr(viewset, action):
3739
bound_actions[method] = action
3840

41+
# Build the url pattern
3942
regex = prefix + suffix
4043
view = viewset.as_view(bound_actions)
4144
name = name_format % base_name
4245
ret.append(url(regex, view, name=name))
46+
47+
# Bind any extra @action or @link routes
48+
for attr in dir(viewset):
49+
func = getattr(viewset, attr)
50+
http_method = getattr(func, 'bind_to_method', None)
51+
if not http_method:
52+
continue
53+
54+
regex_format, name_format = self.extra_routes
55+
56+
# Build the url pattern
57+
regex = regex_format % attr
58+
view = viewset.as_view({http_method: attr}, **func.kwargs)
59+
name = name_format % (base_name, attr)
60+
ret.append(url(regex, view, name=name))
61+
62+
# Return a list of url patterns
4363
return ret

0 commit comments

Comments
 (0)
0