Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DRF reverse action url from viewset

I have an issue reversing the URL of ViewSet actions in the DRF my codes are below, I try some methods to reverse URLs but also you can see it's not working for me

view.py

class Device_API(ViewSet):
   
    def list(self, request) -> Response:
        ...

    def update(self, request, pk) -> Response:
        ...
    
    def create(self, request) -> Union[Response, Http404]:
        ...

    
    def destroy(self, request, pk) -> Union[Response, None]:
        ...

    
    @ action(
        detail=False,
        methods=["GET"],
        url_path=r"filter/(?P<type>\w+)",
        url_name="filter_type",
    )
    def filter(self, request, type) -> Union[Response, Http404]:
        ...

    @ action(detail=True, methods=["GET"], url_name="data")
    def data(self, request, pk) -> Union[Response, Http404]:
        ...

urls.py

from rest_framework.routers import DefaultRouter, SimpleRouter
from .views import Device_API

Router = DefaultRouter()
app_name = "api"

Router.register("device", Device_API, basename="Device")
urlpatterns = Router.urls

and I try to reverse the URL like below but I get an error

view = Device_API()
        view.basename = "Device"
        view.request = None
        url = view.reverse_action('filter')

or

url = reverse('Device-filter')

Error

django.urls.exceptions.NoReverseMatch: Reverse for 'Device-filter' not found. 'Device-filter' is not a valid view function or pattern name.

I and also tried this

url = reverse('api:Device-filter')

Error

Traceback (most recent call last):
  File "/home/nova/Documents/projects/webserver/ENV/lib/python3.8/site-packages/django/urls/base.py", line 71, in reverse
    extra, resolver = resolver.namespace_dict[ns]
KeyError: 'api'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/nova/Documents/projects/webserver/webserver-iot/WEB_SERVER/tests/test_api_v1.py", line 63, in test_test
    url = reverse('api:Device-list')
  File "/home/nova/Documents/projects/webserver/ENV/lib/python3.8/site-packages/django/urls/base.py", line 82, in reverse
    raise NoReverseMatch("%s is not a registered namespace" % key)
django.urls.exceptions.NoReverseMatch: 'api' is not a registered namespace
like image 619
Nova Avatar asked Sep 17 '25 02:09

Nova


2 Answers

I solved this problem by adding a namespace into URLs in urls.py in settings like this

urls.py

path("", include("my_app.urls", "API")),

I could retrieve URLs by these methods

from django.urls import reverse or from rest_framework.reverse import reverse

url = reverse("API:Device-list") 
#              {basenam}-method-name

and you can set the basename for your view in this way

my_app/urls.py

from rest_framework.routers import DefaultRouter
from .views import My_View

Router = DefaultRouter()
Router.register("device", Device_API, basename="Device")
urlpatterns = Router.urls
like image 177
Nova Avatar answered Sep 19 '25 16:09

Nova


I know this topic is old but I ended up here dealing with the same problem and I solved it with the DRF documentation.

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

there is a small section here called Routing for extra actions . The path gets created automatically inside the router but its "hyponated".

I was dealing with a similar problem. and tried reversing as follows

my view was:

@action(detail=True, methods=['PATCH']) 
def join_event(self, request, pk=None):

I tried reversing like this... and it did not work..

url = reverse('tournament:tevent-join_event')

After reading the documentation I realized that it gets automatically converted to hyphons like this

url = reverse('tournament:tevent-join-event')

Even better.. when passing arguments the final path ended being:

url = reverse('tournament:tevent-join-event', kwargs={'pk': self.tevent.id})
# "/api/tournament/tevent/{pk}/join-event"

So it gets the detail view first and patches the proper action

Hope someone finds it usefull!

like image 25
Metche216 Avatar answered Sep 19 '25 15:09

Metche216