router registration order influences output

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



router registration order influences output



I am facing a strange issue trying to implement a webservice using django rest frameworks. I have this two APIs - one for getting the list of news based on category(provided as URL parameter) and another to get the details of a news provided the news ID(provided as url parameter). Following is my app's urls.py code:


urls.py


from django.urls import path
from rest_framework import routers
...
router = routers.DefaultRouter()
router.register('news_contents', NewsContentViewSet)
router.register('news_infos', NewsInfoViewSet)
router.register('categories', CategoryViewSet)
router.register(r'^articles/(?P<category_name>[-w]+)', NewsItemViewSet, base_name="NewsInfo")
router.register(r'^articles/(?P<news_id>d+)/details', NewsDetailViewSet, base_name="NewsInfo")

urlpatterns = router.urls



The above code on calling:
http://localhost:8000/rest/articles/categoryname
returns the correct output, but calling:
http://localhost:8000/rest/articles/4057/details/
returns the following:


"detail":"Not found."



But when I change the order in which these two APIs are registered, both APIs start to work as expected.



Working urls.py:


urls.py


from django.urls import path
from rest_framework import routers
...
router = routers.DefaultRouter()
router.register('news_contents', NewsContentViewSet)
router.register('news_infos', NewsInfoViewSet)
router.register('categories', CategoryViewSet)
router.register(r'^articles/(?P<news_id>d+)/details', NewsDetailViewSet, base_name="NewsInfo") #brought to above the listing API
router.register(r'^articles/(?P<category_name>[-w]+)', NewsItemViewSet, base_name="NewsInfo")

urlpatterns = router.urls



Why is this happening? I am getting a feeling that as I add more APIs, whatever the reason behind this is going to get me stuck.



Another thing I noticed while debugging this was that, there are plenty of other endpoints which I don't want are automatically getting listed as available endpoints:


Using the URLconf defined in restnews.urls, Django tried these URL patterns, in this order:
rest/ ^news_contents/$ [name='newscontent-list']
rest/ ^news_contents.(?P<format>[a-z0-9]+)/?$ [name='newscontent-list']
rest/ ^news_contents/(?P<pk>[^/.]+)/$ [name='newscontent-detail']
rest/ ^news_contents/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='newscontent-detail']
rest/ ^news_infos/$ [name='newsinfo-list']
rest/ ^news_infos.(?P<format>[a-z0-9]+)/?$ [name='newsinfo-list']
rest/ ^news_infos/(?P<pk>[^/.]+)/$ [name='newsinfo-detail']
rest/ ^news_infos/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='newsinfo-detail']
rest/ ^^categories/$/$ [name='newsinfo-list']
rest/ ^^categories/$.(?P<format>[a-z0-9]+)/?$ [name='newsinfo-list']
rest/ ^^categories/$/(?P<pk>[^/.]+)/$ [name='newsinfo-detail']
rest/ ^^categories/$/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='newsinfo-detail']
rest/ ^^articles/(?P<news_id>d+)/details/$ [name='NewsInfo-list']
rest/ ^^articles/(?P<news_id>d+)/details.(?P<format>[a-z0-9]+)/?$ [name='NewsInfo-list']
rest/ ^^articles/(?P<news_id>d+)/details/(?P<pk>[^/.]+)/$ [name='NewsInfo-detail']
rest/ ^^articles/(?P<news_id>d+)/details/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='NewsInfo-detail']
rest/ ^^articles/(?P<category_name>[-w]+)/$ [name='NewsInfo-list']
rest/ ^^articles/(?P<category_name>[-w]+).(?P<format>[a-z0-9]+)/?$ [name='NewsInfo-list']
rest/ ^^articles/(?P<category_name>[-w]+)/(?P<pk>[^/.]+)/$ [name='NewsInfo-detail']
rest/ ^^articles/(?P<category_name>[-w]+)/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='NewsInfo-detail']
rest/ ^$ [name='api-root']
rest/ ^.(?P<format>[a-z0-9]+)/?$ [name='api-root']



I have only provided 5 end points and all the remaining ones are not needed and hence need to be removed. Are these issues somehow connected? How can I solve these?




1 Answer
1



This is how the combination of ModelViewset and DefaultRouter class behave. From the DRF Doc, it provides a bunch of end-point by default
which is very very handy if you are doing CRUD Operations.


From your description, I understood that you are not dealing with CRUD operations, and hence you can't use the Magic of the DefaultRouter and ModelViewset.


So, What I suggest is, use rest_framework.views.APIView class for your purpose.


Example


CRUD


CRUD


DefaultRouter


ModelViewset


rest_framework.views.APIView


Example


views.py


from rest_framework.views import APIView
from rest_framework.response import Response


class MyViewClass(APIView):
def get(self, *args, **kwargs): # This fucntion will handle your "HTTP GET" requests
# put your logic here
return Response(data="mymsg": "this is my response")

def post(self, *args, **kwargs):
return Response("This is post method")



and in your urls.py


urls.py


from django.conf.urls import url

urlpatterns = [
url(r'mysample/', MyViewClass.as_view())

]




References

1. DRF Router

2. DRF viewset

3. DRF APIview


UPDATE-1

Read the Django document



How Django processes a request



When a user requests a page from your
Django-powered site, this is the algorithm the system follows to
determine which Python code to execute:





Currently I am using ModelViewSet, I need to change that?
– Harikrishnan
Aug 12 at 8:01





AFAIK, you can't remove those auto-generated urls if you are using Router and if you are not using the router, you have to manually put all the URL patterns, which is a kind of reinventing the wheel
– JPG
Aug 12 at 8:06



Router





Is your api provides CRUD functionality?
– JPG
Aug 12 at 8:07



CRUD





updated the answer. don't miss the 3rd point
– JPG
Aug 12 at 8:16





Sure, first let me look into what CRUD is. I am frontend guy, just putting my head into backed technologies. SO pretty new with all these terms.
– Harikrishnan
Aug 12 at 8:29






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

Creating a leaderboard in HTML/JS