hackerman
hackerman

Reputation: 1291

Multiple Integer Arguments in Django Rest Framework Router URL

I'm setting up a url using Django Rest Framework viewsets and routers, and I'm trying to get the url to accept two values: first, to filter objects by a user id, and then by the object's id. (In my case, the objects are from a model called Request.) For example, mysite.com/api/requestsbyuser/1/ would return all Request objects for user 1, and mysite.com/api/requestsbyuser/1/23/ would return Request object with pk=23 for user 1.

Right now I have:

# urls.py

from django.conf.urls import url, include
from rest_framework import routers
from . import views

router = routers.DefaultRouter()
router.register(prefix=r'requestsbyuser/(?P<user_id>.+)', viewset=views.RequestsByUser, base_name='request')

urlpatterns = [
    url(r'^', include(router.urls)),
]

# views.py

class RequestsByUser(viewsets.ModelViewSet):
    serializer_class = RequestsSerializer

    def get_queryset(self):
        u_id = self.kwargs['user_id']
        return Request.objects.filter(user_id=u_id)

This works well for listing all Request objects when the url is passed in only the user_id. But when I try to go to mysite.com/api/requestsbyuser/1/23/, I get the error: invalid literal for int() with base 10: '1/23'.

Django debugging says that the following four url patterns are in my URLConf:

^api/ ^ ^requestsbyuser/(?P<user_id>.+)/$ [name='request-list']
^api/ ^ ^requestsbyuser/(?P<user_id>.+)\.(?P<format>[a-z0-9]+)/?$ [name='request-list']
^api/ ^ ^requestsbyuser/(?P<user_id>.+)/(?P<pk>[^/.]+)/$ [name='request-detail']
^api/ ^ ^requestsbyuser/(?P<user_id>.+)/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='request-detail']

Am I missing something? I thought the DRF router would handle url paths with individual object primary key values, but it seems like it's treating the url after the prefix as an integer and ignoring the /.

Upvotes: 4

Views: 5386

Answers (2)

Henshal B
Henshal B

Reputation: 1972

You'll be only able to use one argument after prefix, in case of DefaultRouter. Otherwise you should you use action decorator. Doc says so.

router.register(r'users', UserViewSet)

will generate

  • URL pattern: ^users/$ Name: 'user-list'
  • URL pattern: ^users/{pk}/$ Name: 'user-detail'

https://www.django-rest-framework.org/api-guide/routers/

Upvotes: 0

luc
luc

Reputation: 43096

Just an idea : Did you try to use \d+ rather than .+ in regex?

router.register(prefix=r'requestsbyuser/(?P<user_id>\d+)', viewset=views.RequestsByUser, base_name='request')

It should force user_id to be a number and so avoid to get 1/23

Upvotes: 8

Related Questions