Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete method on Django Rest Framework ModelViewSet

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

like image 718
NewScientists Avatar asked Sep 05 '17 11:09

NewScientists


People also ask

How do I delete a specific record in Django?

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.

What is Viewsets Modelviewset?

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() .

What is the difference between APIView and ViewSet?

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.

What is QuerySet in Django REST framework?

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.


2 Answers

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:

DefaultRouter class url patterns

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.

like image 66
wencakisa Avatar answered Sep 23 '22 22:09

wencakisa


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

like image 32
Exprator Avatar answered Sep 21 '22 22:09

Exprator