Django

⌘K
  1. Home
  2. Django
  3. Htmx
  4. beginner tutorial
  5. Delete Function

Delete Function

views.py

from django.views.generic import CreateView, ListView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404
from .models import Product
from .forms import ProductForm


class ProductDeleteView(DeleteView):
    model = Product
    success_url = reverse_lazy("product_list")
    
    def post(self, request, *args, **kwargs):
        # Handle both POST and DELETE methods (HTMX sends DELETE as POST with _method=DELETE)
        return self.delete(request, *args, **kwargs)
    
    def delete(self, request, *args, **kwargs):
        # Get the object
        self.object = self.get_object()
        product_id = self.object.id
        
        # Delete the object
        self.object.delete()
        
        # Return appropriate response based on request type
        if request.htmx:
            # For HTMX requests, return empty response to remove the row
            return HttpResponse("")
        else:
            # For non-HTMX requests, redirect to success URL
            return HttpResponseRedirect(self.get_success_url())

urls.py

from django.urls import path
from .views import (

    ProductDeleteView
)

urlpatterns = [
    path("delete/<int:pk>/", ProductDeleteView.as_view(), name="product_delete"),
]

_product_list.html

<div class="overflow-hidden rounded-lg border border-gray-200 shadow-lg">
    <div class="px-6 py-4 border-b border-gray-200 bg-gray-50">
        <div class="flex items-center justify-between">
            <h3 class="text-lg font-semibold text-gray-900">Product Inventory</h3>
            <span class="text-sm text-gray-500">{{ products.count }} items</span>
        </div>
    </div>
    
    <table class="min-w-full divide-y divide-gray-200">
        <thead class="bg-gray-50">
            <tr>
                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Product</th>
                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Price</th>
                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Description</th>
                <th class="px-6 py-3"></th>
            </tr>
        </thead>
        <tbody class="bg-white divide-y divide-gray-200">
            {% for product in products %}
            <tr class="hover:bg-gray-50 transition-colors duration-150">
                <td class="px-6 py-4 whitespace-nowrap">
                    <div class="text-sm font-medium text-gray-900">{{ product.name }}</div>
                </td>
                <td class="px-6 py-4 whitespace-nowrap">
                    <div class="text-sm text-gray-900">${{ product.price }}</div>
                </td>
                <td class="px-6 py-4">
                    <div class="text-sm text-gray-500 max-w-xs truncate">{{ product.description }}</div>
                </td>
                <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
                <!-- Edit Button -->
                    <button hx-get="{% url 'product_edit' product.pk %}"
                    hx-target="#main-content"
                    hx-push-url="true"
                    class="text-blue-600 hover:text-blue-900 mr-4">
                Edit
            </button>
    <!-- Delete Button - Fixed -->
    <button hx-delete="{% url 'product_delete' product.pk %}"
            hx-confirm="Are you sure you want to delete this product?"
            hx-target="closest tr"
            hx-swap="outerHTML"
            class="text-red-600 hover:text-red-900">
        Delete
    </button>
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</div>

base.html

    <script>
        // Ensure HTMX is loaded
        document.addEventListener('DOMContentLoaded', function() {
            // Add CSRF token to all HTMX requests
            document.body.addEventListener('htmx:configRequest', function(event) {
                event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
            });
            
            // Debug HTMX events
            document.body.addEventListener('htmx:beforeRequest', function(event) {
                console.log('HTMX request starting:', event.detail);
            });
            
            document.body.addEventListener('htmx:responseError', function(event) {
                console.error('HTMX request failed:', event.detail);
            });
        });
    </script>

How can we help?