Search code examples
pythondjangohttpcruddjango-class-based-views

How to effectively use PUT and DELETE HTTP methods in Django Class-Based Views?


I'm setting up a CRUD system with Django, using Class-Based Views. Currently I'm trying to figure out how to handle HTTP PUT and DELETE requests in my application. Despite searching the Django documentation extensively, I'm having trouble finding concrete examples and clear explanations of how to submit these types of queries to a class-based view.

I created a view class named CategoryView, extending from: django.views.View, in which I implemented the get and post methods successfully. And I want to build my urls like this:

  1. New Category: 127.0.0.1:8000/backendapp/categories/create
  2. List all Category: 127.0.0.1:8000/backendapp/categories/
  3. Retrieve only one Category: 127.0.0.1:8000/backendapp/categories/1
  4. Etc...

However, when I try to implement the put and delete methods, I get stuck.

For example :


from django.views import View

class CategoryView(View):
     template_name = 'backendapp/pages/category/categories.html'
    
     def get(self, request):
         categories = Category.objects.all()
        
         context = {
             'categories': categories
         }
        
         return render(request, self.template_name, context)
    
     def post(self, request):
         return
        
     def delete(self, request, pk):
         return
        
     def put(self, request):
         return

I read through the Django documentation and found that Class-Based Views support HTTP requests: ["get", "post", "put", "patch", "delete", "head ", "options", "trace"]. link: https://docs.djangoproject.com/en/5.0/ref/class-based-views/base/#django.views.generic.base.View

Despite this, I can't figure out how to do it.

So I'm asking for your help to unblock me.

I looked at the Django documentation and searched online for examples and tutorials on handling HTTP requests in class-based views. I also tried experimenting with adding the put and delete methods to my CategoryView view class, but without success. I expected to find resources that clearly explain how to integrate these queries into my Django application, as well as practical examples demonstrating their use. However, I haven't found a working solution and am now seeking help from the community to overcome this difficulty.


Solution

  • Beware that HTML does not support PUT, PATCH, DELETE "out of the box". You can use AJAX, but <form method="delete"> does not work, simply because the browser does not make a DELETE request. So you will need AJAX to make the request.

    Another problem is the routing: your view sits behind categories/, so that is where you then would make the PUT, PATCH, etc. requests. You will thus need to define multiple views, that each handle part of it, like:

    from django.urls import path
    
    urlpatterns = [
        path('categories/', MyListlikeCategoryView.as_view()),
        path('categories/<int:pk>/', MyObjectlikeCategoryView.as_view()),
        path('categories/create/', MyCreateCategoryView.as_view()),
    ]

    and then in these separate views, implement the applicable methods:

    class MyListlikeCategoryView(View):
        # list of categories
        def get(self, request):
            # …
            pass
    
    
    class MyObjectlikeCategoryView(View):
        # put new object
        def put(self, request, pk):
            # …
            pass
    
        # update object
        def patch(self, request, pk):
            # …
            pass
    
        # delete object
        def delete(self, request, pk):
            # …
            pass
    
    
    class MyCreateCategoryView(View):
        # create object
        def post(self, request):
            # …
            pass

    But regardless, Django is not designed to make (CRUD) APIs. What you can use to make such APIs is a ModelViewSet (or ViewSet) from the Django REST framework [drf-doc]. This also provides serializers that normally make the mapping between the request data and a model object, and from a model object to response data easier, and works with a router that thus then can route the items properly.

    We thus can implement that then with:

    class MyCategoryViewSet(viewsets.ViewSet):
        # GET /categories/
        def list(self, request):
            # …
            pass
    
        # POST /categories/
        def create(self, request):
            # …
            pass
    
        # GET /categories/1/
        def retrieve(self, request, pk=None):
            # …
            pass
    
        # PUT /categories/1/
        def update(self, request, pk=None):
            # …
            pass
    
        # PATCH /categories/1/
        def partial_update(self, request, pk=None):
            # …
            pass
    
        # DELETE /categories/1/
        def destroy(self, request, pk=None):
            # …
            pass

    The paths are not determined by the ViewSet though, the comment at the top of each mehtod is just how a SimpleRouter [drf-doc] would do this. You thus register the ViewSet with:

    from rest_framework import routers
    
    router = routers.SimpleRouter()
    router.register('categories', MyCategoryViewSet)
    urlpatterns = router.urls