Reverse to @list_route with custom url_path

If I have a viewet 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 calls a NoReverseMatch . Examining url patterns (by navigating to a nonexistent URL) reveals 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'] 

extraroute-arguments/(?P<thing>[^/]+) view name seem extraroute-arguments/(?P<thing>[^/]+) instead of extraroute-arguments ? And indeed, if I use reverse('extraroute-arguments/(?P<thing>[^/]+)', kwargs={'thing': 'something'}) , this works. Am I missing something very obvious here, or is this a bug in the django-rest-framework ?

This uses Django 1.8a and django-rest-framework 3.0.5.

+6
source share
1 answer

Ok, in the second example, you send url_path='arguments/(?P<thing>[^/]+)' . The Django REST framework use it to create both a URL pattern and a URL Name . But the implementation is too clean to remove the regex expression.

Custom Router Solution

 #inside urls.py router = SimpleRouter() router.routes.append( Route( url=r'^{prefix}/arguments/(?P<thing>[^/]+)$', name='{basename}-arguments', mapping={ 'get': 'arguments', }, initkwargs={} ), ) router.register('extraroute', ExtraRouteViewset, base_name='extraroute') urlpatterns = router.urls 

and then in views.py remove the @list_route decorators since it is no longer needed (and will cause a route collision)

 #inside views.py class ExtraRouteViewset(viewsets.GenericViewSet): #... def arguments(self, request, thing): return Response({ 'key': thing, 'reverse': reverse('extraroute-arguments', kwargs={'thing': 'something'}), }) 

I should mention that this actually adds a hard-coded Route pattern inside the standard SimpleRouter (which has patterns for list, create, retrieve, update, partial update, destroy). This means that every view that is registered through this instance of the router will be able to implement the arguments method, and this method will be called when the regular expression matches it.

+6
source

Source: https://habr.com/ru/post/983283/


All Articles