2

I am using drf-nested-router something like the following in my url.py

router = SimpleRouter()
profile_router = routers.NestedSimpleRouter(router, r'profile', lookup='user')
profile_router.register(r'comments', UserCommentViewSet, basename='profile-comments')

The viewset is

class UserCommentViewSet(CommentViewSet):
    def get_queryset(self):
        return Comment.objects.filter(owner=self.request.user)

So the URL is something like,

mydomain.com/profile/{profile_id}/comments/

it gives me right results. But the following URL is also giving me right results,

mydomain.com/profile/{anything}/comments/

because I am using the session user info to filter the data. Is it possible to make the URL like

mydomain.com/profile/comments/
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
sadat
  • 4,004
  • 2
  • 29
  • 49
  • Have you considered creating a viewset for profile. And adding an @action(detail=False) for comments? – Yuval Feb 01 '21 at 08:37

1 Answers1

2

Based on your code:

router = SimpleRouter()
# router.register('users', UserViewSet, 'user')
profile_router = routers.NestedSimpleRouter(router, r'profile', lookup='user')
profile_router.register(r'comments', UserCommentViewSet, basename='profile-comments')

You are interpreting this in a wrong way. Here's how you can use NestedSimpleRouter

mydomain.com/profile/ # list all the users.
mydomain.com/profile/{profile_id} # retrieve particular user based on profile_id/user_id/pk.
mydomain.com/profile/{profile_id}/comments/ # list all the comments belong to a particular user (not the current session user) based on profile_id/user_id.
mydomain.com/profile/{profile_id}/comments/{comment_id} # retrieve particular comment based on comment_id.

This url:

mydomain.com/profile/{anything}/comments/

is working because you are filtering by owner = request.user.

And this url:

mydomain.com/profile/{profile_id}/comments/

is supposed to give list of all comments by taking profile_id in UserCommentViewSet. So your view will be like:

class UserCommentViewSet(CommentViewSet):
    def get_queryset(self):
        return Comment.objects.filter(owner__id=profile_id)

In simple words you can use NestedSimpleRouter to get all users, user detail, all comments posted by single user and comment detail.

Solution:

If you need only current (session) user comments (since you dont need all comments by all users), you need something like:

router = SimpleRouter()
router.register(r'profile/comments', UserCommentViewSet, basename='profile-comments')

and the UserCommentViewSet is:

class UserCommentViewSet(CommentViewSet):
    def get_queryset(self):
        return Comment.objects.filter(owner=self.request.user)

Then, this url:

mydomain.com/profile/comments/

will give all comments as required.

Siva Sankar
  • 1,672
  • 1
  • 9
  • 16
  • Thanks for your answer. However, I tried that and its not working. The error message is "detail": "Not found." – sadat Jan 28 '21 at 01:46
  • I just found the reason, 'profile' is already registered, that is why 'profile/something' is giving not found. Do you know how to solve this problem? – sadat Jan 28 '21 at 01:50
  • I didn't gave code for profile/something. Its won't work. Please read the answer carefully. You don't need comments by all users, right? You only need the current session user comments in the url profile/comments. That's what you asked in the question. Now don't use profile/something. Just use profile/comment. If still the error persists. Would you post all the error? – Siva Sankar Jan 28 '21 at 05:37
  • sorry for the misunderstanding. What I meant is, I have a URL /profile and /profile/comments. Now /profile/comments only works when I comment /profile URL. – sadat Jan 29 '21 at 01:57
  • what you want to show in /profile? all users or the current session request.user? – Siva Sankar Jan 29 '21 at 05:49
  • does it really matter? lets say /profile just a hello world and /profile/comments is hello mars. Both of them does not work at the same time, that what I tried to mean. – sadat Jan 29 '21 at 10:40
  • Yes. It matters the most. NestedSimpleRouter is designed for that. Also you have url profile/ for users when you mentioned lookup='user'. That means it will give list of all user profiles. – Siva Sankar Jan 29 '21 at 16:31
  • I think we are not on the same page. The purposes of /profile and /profile/comment are important. The problem is they do not work at the same time regardless what they return. please correct me if I am wrong. – sadat Jan 31 '21 at 23:34
  • When we give lookup='user' for /profile/ it will create two urls 1. /profile/ 2. /profile/. this is fixed. In short, if /profile/ with lookup='user' has to work, then we can't create /profile/comments/. – Siva Sankar Feb 01 '21 at 07:25
  • that is my problem. I already have /profile and /profile/{id}/comments (with nested router). now how can I achieve /profile/comments.. but really Thanks for your replies. – sadat Feb 01 '21 at 12:08
  • You can't achieve that using NestedRouter, you have to create singe individual apis. Infact you don't need NestedRouter. – Siva Sankar Feb 01 '21 at 12:40