14

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?

ilse2005
  • 9,587
  • 4
  • 42
  • 65
Fomalhaut
  • 5,473
  • 6
  • 25
  • 62
  • 1
    Strange. The code you posted is working for me. Is this the full code? – ilse2005 Mar 15 '16 at 12:49
  • Not exactly, I placed the parts that I find important. Any idea, where I can be wrong? – Fomalhaut Mar 15 '16 at 12:59
  • 2
    Well I copied the code from your question and it works. There has to be some other problem. What DRF version are you using? – ilse2005 Mar 15 '16 at 13:10
  • 4
    Thanks, I found the problem. I just included `url(r'^api/', include(views.router.urls))` before and the `router` contains a pattern called `index`. In other words I had another view which took my response and rejected it cause of method = POST. – Fomalhaut Mar 15 '16 at 13:32
  • 1
    @Fomalhaut Thank you for including your solution! I made the same mistake. – ThePadawan Jan 08 '18 at 16:04
  • @Fomalhaut Please post your comment in the solution section to increase its visibility. – Arka Ghosh Jan 07 '20 at 06:35

5 Answers5

4

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)]
lospejos
  • 1,888
  • 3
  • 17
  • 31
M.Void
  • 2,128
  • 2
  • 24
  • 37
3

You need to change just:

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

    def post(self, request, format=None):
        return Response("ok")
SuReSh
  • 1,543
  • 1
  • 21
  • 43
1
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

barbsan
  • 3,238
  • 11
  • 18
  • 27
Prasad Giri
  • 108
  • 7
1

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')
Santi Rodriguez
  • 126
  • 1
  • 8
1

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')
Kurt Brown
  • 21
  • 1
  • 4