@@ -160,57 +160,47 @@ def get_routes(self, viewset):
160
160
# converting to list as iterables are good for one pass, known host needs to be checked again and again for
161
161
# different functions.
162
162
known_actions = list (flatten ([route .mapping .values () for route in self .routes if isinstance (route , Route )]))
163
-
164
- # Determine any `@detail_route` or `@list_route` decorated methods on the viewset
165
- detail_routes = []
166
- list_routes = []
167
- for methodname in dir (viewset ):
168
- attr = getattr (viewset , methodname )
169
- httpmethods = getattr (attr , 'bind_to_methods' , None )
170
- detail = getattr (attr , 'detail' , True )
171
- if httpmethods :
172
- # checking method names against the known actions list
173
- if methodname in known_actions :
174
- raise ImproperlyConfigured ('Cannot use @detail_route or @list_route '
175
- 'decorators on method "%s" '
176
- 'as it is an existing route' % methodname )
177
- httpmethods = [method .lower () for method in httpmethods ]
178
- if detail :
179
- detail_routes .append ((httpmethods , methodname ))
180
- else :
181
- list_routes .append ((httpmethods , methodname ))
182
-
183
- def _get_dynamic_routes (route , dynamic_routes ):
184
- ret = []
185
- for httpmethods , methodname in dynamic_routes :
186
- method_kwargs = getattr (viewset , methodname ).kwargs
187
- initkwargs = route .initkwargs .copy ()
188
- initkwargs .update (method_kwargs )
189
- url_path = initkwargs .pop ("url_path" , None ) or methodname
190
- url_path = escape_curly_brackets (url_path )
191
- url_name = initkwargs .pop ("url_name" , None ) or url_path
192
- ret .append (Route (
193
- url = replace_methodname (route .url , url_path ),
194
- mapping = {httpmethod : methodname for httpmethod in httpmethods },
195
- name = replace_methodname (route .name , url_name ),
196
- initkwargs = initkwargs ,
197
- ))
198
-
199
- return ret
200
-
201
- ret = []
163
+ extra_actions = viewset .get_extra_actions ()
164
+
165
+ # checking action names against the known actions list
166
+ not_allowed = [
167
+ action .__name__ for action in extra_actions
168
+ if action .__name__ in known_actions
169
+ ]
170
+ if not_allowed :
171
+ msg = ('Cannot use the @action decorator on the following '
172
+ 'methods, as they are existing routes: %s' )
173
+ raise ImproperlyConfigured (msg % ', ' .join (not_allowed ))
174
+
175
+ # partition detail and list routes
176
+ detail_actions = [action for action in extra_actions if action .detail ]
177
+ list_actions = [action for action in extra_actions if not action .detail ]
178
+
179
+ routes = []
202
180
for route in self .routes :
203
181
if isinstance (route , DynamicDetailRoute ):
204
- # Dynamic detail routes (@detail_route decorator)
205
- ret += _get_dynamic_routes (route , detail_routes )
182
+ routes += [self ._get_dynamic_route (route , action ) for action in detail_actions ]
206
183
elif isinstance (route , DynamicListRoute ):
207
- # Dynamic list routes (@list_route decorator)
208
- ret += _get_dynamic_routes (route , list_routes )
184
+ routes += [self ._get_dynamic_route (route , action ) for action in list_actions ]
209
185
else :
210
186
# Standard route
211
- ret .append (route )
187
+ routes .append (route )
212
188
213
- return ret
189
+ return routes
190
+
191
+ def _get_dynamic_route (self , route , action ):
192
+ initkwargs = route .initkwargs .copy ()
193
+ initkwargs .update (action .kwargs )
194
+
195
+ url_path = escape_curly_brackets (action .url_path )
196
+
197
+ return Route (
198
+ url = replace_methodname (route .url , url_path ),
199
+ name = replace_methodname (route .name , action .url_name ),
200
+ mapping = {http_method : action .__name__
201
+ for http_method in action .bind_to_methods },
202
+ initkwargs = initkwargs ,
203
+ )
214
204
215
205
def get_method_map (self , viewset , method_map ):
216
206
"""
0 commit comments