405 "Method POST is not allowed" in Django REST framework

Viewed 33681

I am new in Django REST framework. Can someone explain why I get such error, if I make a POST request to '/api/index/'

405 Method Not Allowed
{"detail":"Method \"POST\" not allowed."}

My code is following:

# views.py
class ApiIndexView(APIView):
    permission_classes = (permissions.AllowAny,)

    def post(self, request, format=None):
        return Response("ok")

# urls.py
urlpatterns = [
    url(r'^api/index/$', views.ApiIndexView.as_view()),
]

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.DjangoModelPermissions',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    )
}

But if I add <pk> into my pattern, everything works fine:

# views.py
class ApiIndexView(APIView):
    permission_classes = (permissions.AllowAny,)

    def post(self, request, pk, format=None):
        return Response("ok")

# urls.py
urlpatterns = [
    url(r'^api/index/(?P<pk>\d+)/$', views.ApiIndexView.as_view()),
]

I am completely confused. Why it's necessary to use <pk> and is there a way to avoid the use of this parameter in the URL pattern?

5 Answers

Is allways better not using empty spaces in url names.

So, instead of this:

router.register(r'', views.SomeViewSet, basename='index')

Do this:

router.register(r'some-url-name', views.SomeViewSet, basename='index')
class ApiIndexView(APIView) 

instead of this please import from rest_framework import generics and change it to

class ApiIndexView(generics.ListCreateAPIView) 

There are many generic views. ListCreateAPIView is used for GET and POST and CreateAPIView is used only for POST methods

Your own comment is right. You just included the index url before. And that main view recieve url parameter for retreiving objects, so your new view is interpreted as param. I had the same problem in urls.py:

router = DefaultRouter()
router.register(r'', views.MainViewSet, basename='index')
router.register(r'other_view', views.OtherViewSet, basename='typeservice')

Solution:

router = DefaultRouter()
router.register(r'main', views.MainViewSet, basename='index')
router.register(r'other_view', views.OtherViewSet, basename='other_view')
Related