Reputation: 9825
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
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
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
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
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
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
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
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