2

I'm new to DRF's "viewsets", but I've inherited some problematic code, and am having trouble figuring out what's going on. I have stripped down the code below to isolate the behavior I don't understand.

In my urls.py I have

from my_app.api import CurrentUserViewSet,
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register("me", CurrentUserViewSet, basename="api-me")
print(router.urls)

Note the diagnostic print statement at the end.

The CurrentUserViewSet is defined as:

from rest_framework import viewsets
from django.views.generic import View

class CurrentUserViewSet(viewsets.ViewSetMixin, View):

    def create(self, request):
        """Update current user."""
        instance = request.user
        ...

    @action(detail=False, methods=["post"])
    def some_other_route(self, request):
        ...

When I start a runserver instance that uses the above, it hits my print statement in "urls.py" and displays this:

[
<URLPattern '^me/$' [name='api-me-list']>,
<URLPattern '^me\.(?P<format>[a-z0-9]+)/?$' [name='api-me-list']>,
<URLPattern '^me/some_other_route/$' [name='api-me-some-other-route']>,
<URLPattern '^me/some_other_route\.(?P<format>[a-z0-9]+)/?$' [name='api-me-some-other-route']>...
]

So it looks like the name of my create route is being changed to list. I don't know how or why this is happening. Interestingly, if I define an addtional route that is actually named "list", the "create" method still does not appear in the URLs created by the router. It seems to be totally ignored.

As I mentioned, I inherited this code. I think that even though the original author named this route "create", he was actually trying to update the currently authenticated user (as implied by the docstring). I think he put his custom code in a method called "create" because he wanted to get the user from request.user and not retrieve it from a pk in a signature like def update(self, request, pk=None).

But this doesn't seem to work because execution will never enter that create method. At least, I've never seen it happen.

So my questions are:

  • Would the code above ever have worked, maybe in some earlier version of DRF?
  • If I name a route "create", why/how does it get changed to "list"?
  • If I add a route that is actually named "list", why is the "create" route ignored by DefaultRouter ?
  • What is a better way to update the currently authenticated user that does not take a pk parameter, but just uses request.user?

Many thanks

nttaylor
  • 788
  • 3
  • 11
  • 25
  • `create` a reserved action in DRF, check this page in the docs to see how to use viewsets https://www.django-rest-framework.org/api-guide/viewsets/#viewset-actions – Jimmar Jul 18 '21 at 17:38
  • Thank you @Jimmar - I realize it's a reserved action, but then again, so is "list". I haven't found anything that says that DRF will change the name of one reserved action to another. I'm still looking for an explanation of the described behavior and/or a better way to accomplish my goal. – nttaylor Jul 18 '21 at 18:07
  • 1
    The `-list` url accepts both `GET` and `POST`. If you use that URL with a `GET`, it will call `list`, while using `POST` will call `create`. It's understandable that the naming is a bit confusing, but it does make sense to use just one URL for both creating and listing. You can find the implementation of the mappings [`here`](https://github.com/encode/django-rest-framework/blob/master/rest_framework/routers.py#L91) and the discussion in the docs [`here`](https://www.django-rest-framework.org/api-guide/routers/#simplerouter)(your question is answered by the first row) – Brian Destura Jul 19 '21 at 00:15

0 Answers0