6

I need to pass instance id after last / of my @action name method, and I seriously have no idea how...

I have a UserViewSet, which url to access list is : /users/, then i have action called favorite_posts, which is detail=False because I'm filtering by current logged user, and the action refer to user posts, I wanna be able to pass the post_id like /users/favorite_posts/post_id/, because in this case it's more friendly to me than /users/1/favorite_posts/ which I could obtain setting detail=True.

Is there any way to do that?

slqq
  • 245
  • 2
  • 3
  • 13
  • Isn't it supposed to be `/posts//`? Otherwise you have two paths to the same resource. And I'd suggest to invent something like '/home/' root url for obtaining anything related to _current user_. `/users/` + `/users//` resulting with anything else then list of users and user by id produce ambiguity and misunderstanding of common rest approaches. – Ivan Starostin Nov 29 '18 at 17:23
  • I have manytomany relation inside user to posts, and from this action I wanted to be able to just manipulate that one list, in /posts/ i dont have path to user favorite posts to that only one path to this resource. It seemed to me more logic to manipulate user list on user path, than on post. – slqq Nov 29 '18 at 17:35
  • Yes, you've discovered `favorite_posts` **list with post ids**, now you want to reach **specific post by id**. Post is a separate entity which is expected to be discovered at `/posts//`. – Ivan Starostin Nov 29 '18 at 18:00

3 Answers3

12

You can include parameters in your url pattern and have user_id passed to your method like this:

@action(methods=['post'], detail=False, url_path='favorite_posts/(?P<user_id>\d+)', url_name='favorite-posts')
def get_favorite_post(self, request, user_id):
    # Do something
    return Response({...})
kaveh
  • 2,046
  • 1
  • 21
  • 33
  • Is there any method to url_path='favorite_posts/(?P\d+)' mandatory? I have 'GET', 'POST' and 'DELETE' there, and for get I wanna get list, and pass id only for del and post. – slqq Nov 29 '18 at 17:30
  • 1
    @slqq I'm not sure if I followed. You can use any method you like. As for your other question above about having `user_id` optional, you need to modify the regex in `url_pattern` to something like this: `favorite_posts/(?P\d*)`. This way `user_id` can be between zero and any number of digits. – kaveh Nov 29 '18 at 18:18
  • @slqq still, I recommend separating your methods for list and details, instead of having one action method taking care of different things. – kaveh Nov 29 '18 at 18:19
  • When I use 'favorite_posts/(?P\d*)' i lose chance to not pass this argument, it's required in this way, even I set user_id=False in method arguments. – slqq Nov 29 '18 at 20:06
5

You can use it like this:

@action(methods=['get'], detail=False, url_path='req/(?P<post_id>\d+)')

and get post_id in your method like this: kwargs.get('post_id') or just pass post_id directly to your method.

@action(methods=['get'], detail=False, url_path='req/(?P<post_id>\d+)')
def get_post(request, post_id):
     .....
Reza Torkaman Ahmadi
  • 2,958
  • 2
  • 20
  • 43
0

This only works with r because its regex use url_path=r'favorite_posts/(?P<user_id>\d+)', url_name='favorite-posts'