Fomalhaut
Fomalhaut

Reputation: 9825

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

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?

Upvotes: 23

Views: 50736

Answers (7)

Fravel
Fravel

Reputation: 187

For me it was because I forgot to specified the id in the url /api/user/{missing_id} in a PATCH request. So it is not your case but could help other reader.

Upvotes: 0

NetrobeWebby
NetrobeWebby

Reputation: 116

Had the exact issue too, solved it like this.

My previous code

urlpatterns = [
    path('', views.CurriculumList.as_view(), name='list-curriculum'),
    path(
        '<slug:slug>/', views.SingleCurriculum.as_view(),
        name='get-curriculum'),
    path(
        'enroll/', views.EnrollCurriculum.as_view(),
        name='enroll-curriculum'),
]

The problem here was that when i visit url enroll/ django maps the request to the first match, which is <slug:slug>/. All i had to do was change the order, so that the actual Enroll views takes precedence.

New code

urlpatterns = [
    path('', views.CurriculumList.as_view(), name='list-curriculum'),
    path(
        'enroll/', views.EnrollCurriculum.as_view(),
        name='enroll-curriculum'),
    path(
        '<slug:slug>/', views.SingleCurriculum.as_view(),
        name='get-curriculum'),
]

Upvotes: 1

Kurt Brown
Kurt Brown

Reputation: 39

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')

Upvotes: 2

Santi Rodriguez
Santi Rodriguez

Reputation: 304

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')

Upvotes: 1

Prasad Giri
Prasad Giri

Reputation: 118

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

Upvotes: 2

M.Void
M.Void

Reputation: 2904

Make sure that you have "POST" in http_method_names. Alternatively, you can write it like this:

def allowed_methods(self):
    """
    Return the list of allowed HTTP methods, uppercased.
    """
    self.http_method_names.append("post")
    return [method.upper() for method in self.http_method_names
            if hasattr(self, method)]

Upvotes: 4

SuReSh
SuReSh

Reputation: 1511

You need to change just:

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

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

Upvotes: 1

Related Questions