1

I have a small React/Django blog app and I'm trying to change the behavior on a DELETE request. Specifically I want to check if the post in the database has a field called "protected" equal to true or not, and fail if true.

At some point before this, deleting posts worked fine. When I overloaded the destroy method in PostView in views.py below, I noticed that it didn't work. The destroy method is never called - I never see the print statement inside. The server responds with a 405 and never calls destroy. Here's the error:

Method Not Allowed (DELETE): /api/posts/3
Method Not Allowed: /api/posts/3
[29/Nov/2020 17:03:04] "DELETE /api/posts/3 HTTP/1.1" 405 0

If I remove my destroy method, it still doesn't work like it did previously, so I think I broke something unrelated. What am I missing?

Here's my urls.py:

from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static

from django.urls import path, include, re_path                 
from rest_framework import routers
from server import views
from .views import index                        

router = routers.DefaultRouter()                      
router.register(r'posts', views.PostView, 'post')     

urlpatterns = [
    path('', index, name='index'),
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
    re_path(r'^(?:.*)/?$', index, name='index'),           
]+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

and views.py:

from rest_framework import viewsets, status

from .serializers import PostSerializer      
from .models import Post

from rest_framework.response import Response

from server.models import Post

class PostView(viewsets.ModelViewSet):  
  serializer_class = PostSerializer          
  queryset = Post.objects.all()  

  def list(self, request):
    queryset = Post.objects.all()  

    serializer = PostSerializer(queryset, many=True)
    return Response(serializer.data)

  def update(self, request, pk=None):
    queryset = Post.objects.all().filter(pk=pk)
    post = queryset[0]

    if post.protected == False:
      post.title = request.data['title']
      post.body = request.data['body']
      post.save()
      return Response("Post updated")
    else:
      return Response("Post protected", status=status.HTTP_403_FORBIDDEN)

  def destroy(self, request, pk=None):
    print("In destroy!!!!!!!")
    queryset = Post.objects.all().filter(pk=pk)
    post = queryset[0]

    if post.protected == False:
      post.delete()
      return Response("Post deleted")
    else:
      return Response("Post protected", status=status.HTTP_403_FORBIDDEN)

Here's where the delete request is made, in the React front end:

    axios.delete("/api/posts/" + postId)
        .then(post => dispatch(postDeleted(post)))
        .then(() => dispatch(fetchPosts()))
        .catch(errmess => dispatch(postDeleteFailed(errmess)));
3
  • please show your app's urls (router.urls) Commented Nov 29, 2020 at 22:24
  • Hi, 405 means the server does not allow such method. I think it is most likely related to the fact that in DRF, certain views cannot take DELETE method. check out this post stackoverflow.com/questions/26711975/… Commented Nov 29, 2020 at 22:32
  • I saw that post but nothing in it seems relevant. I added the CORS_ALLOW_METHODS list to explicity allow DELETE but there was no change. Also the urls.py file is above - it's the only one I use in the project. Commented Nov 29, 2020 at 22:44

1 Answer 1

1

I think your problem is that your urls are overriding each other. And the problem is the regex pattern of re_path(r'^(?:.*)/?$', index, name='index'). and hence it redirects your request to wrong url and because that view does not support DELETE method it will return 405 status code (method not allowed). So you should delete this url, or change the regex of it (Because almost every patterns fall in it's category), or change your request url from axios.delete("/api/posts/" + postId) to axios.delete("/api/posts/" + postId + '/') (your url should have the trailing slash). I hope this can solve your problem.

Sign up to request clarification or add additional context in comments.

1 Comment

Interesting thank you! That was it. I put in the catch all so that any other page req would be directed to the front end, in case someone followed a link to the /about.html page without having loaded the front end app, for example, which wouldn't be redirected to the front end otherwise. I'll have to figure something else out. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.