Django

⌘K
  1. Home
  2. Django
  3. Htmx
  4. beginner tutorial
  5. Edit function

Edit function

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 ProductUpdateView(UpdateView):
    model = Product
    form_class = ProductForm
    template_name = "products/product_form.html"
    success_url = reverse_lazy("product_list")

    def get_template_names(self):
        if self.request.htmx:
            return ["products/_product_form.html"]
        return super().get_template_names()

    def form_valid(self, form):
        response = super().form_valid(form)
        if self.request.htmx:
            return render(self.request, "products/_product_list.html", {"products": Product.objects.all()})
        return response

urls.py

from django.urls import path
from .views import (
    ProductUpdateView,
)

urlpatterns = [

    path("edit/<int:pk>/", ProductUpdateView.as_view(), name="product_edit"),
]

list.html

<tbody class="bg-white divide-y divide-gray-200">
    {% for product in products %}
    <tr class="hover:bg-gray-50 transition-colors duration-150" id="product-{{ product.id }}">
        <td class="px-6 py-4 whitespace-nowrap">{{ product.name }}</td>
        <td class="px-6 py-4 whitespace-nowrap">${{ product.price }}</td>
        <td class="px-6 py-4">{{ product.description|truncatechars:50 }}</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>
            
        </td>
    </tr>
    {% endfor %}
</tbody>

form.html

<!-- templates/products/_product_form.html -->
<div class="max-w-2xl mx-auto">
    <!-- Form Header -->
    <div class="mb-8 border-b border-gray-200 pb-4">
        <h2 class="text-3xl font-bold text-gray-900">
            {% if object %}Edit{% else %}Create New{% endif %} Product
        </h2>
        <p class="mt-1 text-sm text-gray-500">
            {% if object %}Update the product details{% else %}Fill the form to add a new product{% endif %}
        </p>
    </div>

    <form method="POST" 
          {% if object %} 
              hx-post="{% url 'product_edit' object.pk %}" 
          {% else %} 
              hx-post="{% url 'product_create' %}" 
          {% endif %}
          hx-target="#main-content">
        
        {% csrf_token %}
        <div class="space-y-6">
            <!-- Name Field -->
            <div class="relative z-0">
                {{ form.name }}
                <label for="{{ form.name.id_for_label }}" 
                       class="absolute left-3 -top-3.5 bg-white px-1 text-gray-600 text-sm transition-all 
                              peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-400 
                              peer-placeholder-shown:top-2 peer-focus:-top-3.5 peer-focus:text-sm peer-focus:text-blue-600">
                    Product Name
                </label>
            </div>

            <!-- Price Field -->
            <div class="relative z-0">
                <div class="relative">
                    <span class="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400">$</span>
                    {{ form.price }}
                    <label for="{{ form.price.id_for_label }}" 
                           class="absolute left-8 -top-3.5 bg-white px-1 text-gray-600 text-sm transition-all 
                                  peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-400 
                                  peer-placeholder-shown:top-2 peer-focus:-top-3.5 peer-focus:text-sm peer-focus:text-blue-600">
                        Price
                    </label>
                </div>
            </div>

            <!-- Description Field -->
            <div class="relative z-0">
                {{ form.description }}
                <label for="{{ form.description.id_for_label }}" 
                       class="absolute left-3 -top-3.5 bg-white px-1 text-gray-600 text-sm transition-all 
                              peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-400 
                              peer-placeholder-shown:top-2 peer-focus:-top-3.5 peer-focus:text-sm peer-focus:text-blue-600">
                    Description
                </label>
            </div>

            <!-- Form Actions -->
            <div class="pt-6 border-t border-gray-200 flex justify-end space-x-4">
                <a href="{% url 'product_list' %}" 
                   hx-get="{% url 'product_list' %}" 
                   hx-target="#main-content"
                   class="px-6 py-2.5 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 transition-colors">
                    Cancel
                </a>
                <button type="submit" 
                        class="px-6 py-2.5 bg-gradient-to-r from-blue-600 to-purple-600 text-white 
                               rounded-lg shadow-md hover:shadow-lg transition-all duration-200">
                    {% if object %}Update{% else %}Create{% endif %} Product
                </button>
            </div>
        </div>
    </form>
</div>

How can we help?