Django REST Framework中POST方法不允许错误排查求助
排查POST请求"Method not allowed"错误的原因
问题概述
已在Post_View类中实现post方法,但向http://127.0.0.1:8000/api/v1/posts/端点发送POST请求时,返回错误:{"detail": "Method \"POST\" not allowed."},API其他功能正常。
相关代码配置
project.urls
from django.contrib import admin from django.urls import path, include from rest_framework_simplejwt import views as jwt_views from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path('admin/', admin.site.urls), path('api/v1/token/', jwt_views.TokenObtainPairView.as_view(), name='token_obtain_pair'), path('api/v1/token/refresh/', jwt_views.TokenRefreshView.as_view(), name='token_refresh'), path('api/v1/', include('authentication.urls')), path('api/v1/', include('posts.urls')), # This includes the posts app URLs path('api/v1/payments/', include('payments.urls')), path('api/v1/support/', include('support.urls')), ] if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
posts.urls
from django.urls import path from .views import Lenta_View, Post_View, Profile_View, Settings_View, Like_View, Posts_search, Bookmark_View, Separated_lenta urlpatterns = [ path('', Lenta_View.as_view(), name='lenta'), path('<slug:filter>/', Separated_lenta.as_view(), name='lenta'), path('posts/', Post_View.as_view(), name='post_list_create'), path('posts/<int:id>/', Post_View.as_view(), name='post_detail'), path('profile/', Profile_View.as_view(), name='profile_mine'), path('profile/<slug:username>/', Profile_View.as_view(), name='profile_other'), path('settings/', Settings_View.as_view(), name='settings'), path('like/', Like_View.as_view(), name='like_all'), path('like/<int:id>/', Like_View.as_view(), name='like_add'), path('search', Posts_search.as_view(), name='search'), path('bookmarks/', Bookmark_View.as_view(), name='bookmark_list'), path('bookmarks/<int:id>/', Bookmark_View.as_view(), name='bookmark_add'), ]
Post_View
class Post_View(APIView): permission_classes = [IsAuthenticated] parser_classes = [MultiPartParser, FormParser] def get(self, request, *args, **kwargs): id = kwargs.get("id") user = request.user if id is None: return Response({'message': "You haven't provided an ID"}, status=status.HTTP_400_BAD_REQUEST) post_obj = get_object_or_404(FoodPost, id=id) if post_obj.is_public ==False and post_obj.created_by !=user: return Response({'message': "sorry it`s private meal"}, status=status.HTTP_400_BAD_REQUEST) ser = FPost_serializer(post_obj, context={'request': request}) return Response({'data': ser.data}, status=status.HTTP_200_OK) def post(self, request): data = request.data user = request.user post_ser = FPost_serializer(data=data, context={'request': request}) post_ser.is_valid(raise_exception=True) post_ser.save(created_by=user) return Response({'data': post_ser.data}, status=status.HTTP_201_CREATED) def patch(self, request, *args, **kwargs): data = request.data user = request.user id = kwargs.get("id") if id is None: return Response({'message': "You haven't provided an ID"}, status=status.HTTP_400_BAD_REQUEST) post_obj = get_object_or_404(FoodPost, id=id) if post_obj.created_by != user: return Response({'message': "You do not have permission to edit this post"}, status=status.HTTP_403_FORBIDDEN) if 'images' in data: images = request.FILES.getlist('images') for image in images: ImagePost.objects.create(post=post_obj, image=image) post_ser = FPost_serializer(post_obj, data=data, partial=True, context={'request': request}) post_ser.is_valid(raise_exception=True) post_ser.save() return Response({'post': post_ser.data, 'message': 'Post updated successfully'}, status=status.HTTP_202_ACCEPTED) def put(self,request,*args,**kwargs): data = request.data user= request.user id = kwargs.get("id",None) if id is None: return Response({'message': "You haven't provided an ID"}, status=status.HTTP_400_BAD_REQUEST) post_obj = get_object_or_404(FoodPost, id=id) com_ser = Comment_serializer(data=data) com_ser.is_valid(raise_exception=True) com_ser.save(post_obj=post_obj,commented_by=user) return Response({'comment': com_ser.data, 'message': 'comment uploaded successfully'}, status=status.HTTP_202_ACCEPTED)
错误原因
Django的URL路由采用从上到下优先匹配规则,当请求/api/v1/posts/时,会先匹配到posts.urls中的path('<slug:filter>/', Separated_lenta.as_view(), name='lenta')——Django会把posts当作<slug:filter>的参数值,将请求交给Separated_lenta视图处理。而Separated_lenta类未实现POST方法,因此返回"Method not allowed"错误,根本没有走到Post_View的post方法。
解决方案
调整posts.urls中的路由顺序,将更具体的路径(如posts/)放在通用路径(如空路径、slug参数路径)之前,确保请求能正确匹配到Post_View。修改后的posts.urls如下:
from django.urls import path from .views import Lenta_View, Post_View, Profile_View, Settings_View, Like_View, Posts_search, Bookmark_View, Separated_lenta urlpatterns = [ path('posts/', Post_View.as_view(), name='post_list_create'), path('posts/<int:id>/', Post_View.as_view(), name='post_detail'), path('', Lenta_View.as_view(), name='lenta'), path('<slug:filter>/', Separated_lenta.as_view(), name='lenta'), path('profile/', Profile_View.as_view(), name='profile_mine'), path('profile/<slug:username>/', Profile_View.as_view(), name='profile_other'), path('settings/', Settings_View.as_view(), name='settings'), path('like/', Like_View.as_view(), name='like_all'), path('like/<int:id>/', Like_View.as_view(), name='like_add'), path('search', Posts_search.as_view(), name='search'), path('bookmarks/', Bookmark_View.as_view(), name='bookmark_list'), path('bookmarks/<int:id>/', Bookmark_View.as_view(), name='bookmark_add'), ]
内容的提问来源于stack exchange,提问作者Mishael shpilevsky
相关产品推荐
相关产品推荐

