i have tried to delete a single ManuscriptItem instance using Postman to perform my API requests on against the view below:
class ManuscriptViewSet(viewsets.ModelViewSet):
"""Handles creating, reading and updating items."""
authentication_classes = (TokenAuthentication,)
serializer_class = serializers.ManuscriptItemSerializer
permission_classes = (permissions.PostOwnManuscript, IsAuthenticated,)
def perform_create(self, serializer):
"""Sets the user profile to the logged in user."""
serializer.save(author=self.request.user)
def get_queryset(self):
"""
This view should return a list of all the manuscripts
for the currently authenticated user.
"""
user = self.request.user
return models.ManuscriptItem.objects.filter(author=user)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
The destroy and perform destroy functions are what I have attempted without success. This is what it returns when i tried:
{ "detail": "Method \"DELETE\" not allowed." }
This is how my URLs are currently registered:
router = DefaultRouter()
router.register('manuscripts', views.ManuscriptViewSet, base_name="manuscripts") # auto basename for models
router.register('manuscriptlibrary', views.ManuscriptLibraryViewSet, base_name="manuscript_library")
router.register('manuscriptsettings', views.ManuscriptSettingsViewSet)
urlpatterns = [
url(r'', include(router.urls))
]
I'm i modifying the ModelViewSet wrong do i need to use another approach because of the nature of ModelViewSet? i expected it to work on Postman when i used an Authorized user to Delete a ManuscriptItem instance. In the docs it said Destroy() method can be used.
Additional information
The URL used is:
http://localhost:8000/manuscripts-api/manuscripts/
The model instance to be deleted from:
class ManuscriptItem(models.Model):
"""Represents a single manuscript's content"""
author = models.ForeignKey('accounts_api.UserProfile', on_delete=models.CASCADE)
title = models.CharField(max_length=255)
content = models.CharField(max_length=99999999)
def __str__(self):
"""Django uses when it needs to convert the object to a string"""
return str(self.id)
The way i have tried sending delete requests on postman with json:
{ "manuscript": 7, }
Results: Delete Method not allowed
{ "id": 7, "author": 5, "title": "niceone", "content": "niceone" }
Results: Delete Method not allowed
Additional Questions/Info:
Don't i need to specify the router register with a pk? I tried this but didnt work either:
router.register('manuscripts/{pk}/$', views.ManuscriptViewSet, base_name="manuscript_detail")
Postman says:
Allow →GET, POST, HEAD, OPTIONS
To delete a record we do not need a new template, but we need to make some changes to the members template. Of course, you can chose how you want to add a delete button, but in this example, we will add a "delete" link for each record in a new table column. The "delete" link will also contain the ID of each record.
A ViewSet class is simply a type of class-based View, that does not provide any method handlers such as . get() or . post() , and instead provides actions such as . list() and . create() .
APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc. Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.
The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects. The default behavior of REST framework's generic list views is to return the entire queryset for a model manager.
The issue here is that you send DELETE
request to the wrong url. Look at the DefaultRouter
docs. It generates automatically your urls within your viewset
:
Look closely at the DELETE
method. It is on the {prefix}/{lookup}/[.format]
url pattern. This means that your corresponding router url is manuscripts/<manuscript_id>/
, but you try to send DELETE
request to manuscripts/
only, which is the above pattern. You see directly from the table that the allowed HTTP methods there are GET
and POST
only. That's why you receive MethodNotAllowed
.
The solution to your problem is not to pass the manuscript_id
as a JSON body of the request
{
"manuscript": 7,
}
But to pass it directly to the url:
DELETE
http://localhost:8000/manuscripts-api/manuscripts/7/
And you just register your viewset like:
router.register(r'manuscripts', ManuscriptViewSet.as_view(), name='manuscripts')
As you see, DRF generates the urls automatically for you.
from rest_framework.response import Response
from rest_framework import status
def destroy(self, request, *args, **kwargs):
try:
instance = self.get_object()
self.perform_destroy(instance)
except Http404:
pass
return Response(status=status.HTTP_204_NO_CONTENT)
use this and it will work
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With