If I have a viewset with the following code:
class ExtraRouteViewset(viewsets.GenericViewSet):
@list_route(methods=['get'])
def somefunction(self, request):
return Response({
'key': 'value',
'reverse': reverse('extraroute-somefunction'),
})
@list_route(methods=['get'], url_path='arguments/(?P<thing>[^/]+)')
def arguments(self, request, thing):
return Response({
'key': thing,
'reverse': reverse('extraroute-arguments', kwargs={'thing': 'something'}),
})
I would expect both methods to work. However, the second reverse
raises a NoReverseMatch
. Examining the url patterns (by navigating to a non-existing url) shows the following url patterns:
^demo/ ^ ^extraroute/arguments/(?P<thing>[^/]+)/$ [name='extraroute-arguments/(?P<thing>[^/]+)']
^demo/ ^ ^extraroute/arguments/(?P<thing>[^/]+)/\.(?P<format>[a-z0-9]+)$ [name='extraroute-arguments/(?P<thing>[^/]+)']
^demo/ ^ ^extraroute/somefunction/$ [name='extraroute-somefunction']
^demo/ ^ ^extraroute/somefunction/\.(?P<format>[a-z0-9]+)$ [name='extraroute-somefunction']
The view name seems to be extraroute-arguments/(?P<thing>[^/]+)
instead of extraroute-arguments
? And indeed, if I use reverse('extraroute-arguments/(?P<thing>[^/]+)', kwargs={'thing': 'something'})
it works. Am I missing something very obvious here, or is this a bug in django-rest-framework
?
This is using Django 1.8a and django-rest-framework 3.0.5.
Well, in the second example, you send
url_path='arguments/(?P<thing>[^/]+)'
. Django REST framework use it to create both anURL pattern
and aURL Name
. But the implementation is too pure to strip the regex expression.Solution with a custom router
and then in the views.py remove the
@list_route
decorators since its no more needed (and will cause a route clash)I have to mention that this actually adds a hardcoded
Route
pattern inside the defaultSimpleRouter
(which has patterns for list, create, retrieve, update, partial update, destroy). This means that every viewset which get registered via this router instance will be able to implement anarguments
method and this method will be called when the regex match it.