Add to cart functionality using Django and HTMX

44 Views Asked by At

Hi can you please help me with this problem. I have this code:

models.py

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2)

class Cart(models.Model):
    products = models.ManyToManyField(Product, through='CartItem')

    @property
    def total_price(self):
        return sum(item.product.price * item.quantity for item in self.cartitem_set.all())

class CartItem(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField(default=1)

views.py

from django.shortcuts import render, redirect, get_object_or_404
from .models import Product, Cart, CartItem

def product_list(request):
    products = Product.objects.all()

    # Retrieve or create a cart ID in the session
    cart_id = request.session.get('cart_id')
    cart, created = Cart.objects.get_or_create(id=cart_id)

    # Pass the cart items to the template context
    cart_items = CartItem.objects.filter(cart=cart)
    total_items_in_cart = sum(item.quantity for item in cart_items)
    total_price = cart.total_price

    for item in cart_items:
        item.subtotal = item.product.price * item.quantity

    context = {'products': products, 
               'cart_items': cart_items, 
               'total_items_in_cart': total_items_in_cart, 
               'total_price': total_price}

    return render(request, 'product_list.html', context )

def add_to_cart(request, product_id):
    product = get_object_or_404(Product, id=product_id)
    
    cart_id = request.session.get('cart_id')
    cart, created = Cart.objects.get_or_create(id=cart_id)

    # Check if the product is already in the cart
    cart_item, item_created = CartItem.objects.get_or_create(product=product, cart=cart)

    if not item_created:
        # If the product is already in the cart, update the quantity
        cart_item.quantity += 1
        cart_item.save()

    # Update session with cart ID
    request.session['cart_id'] = cart.id
    request.session.save()

    return render (request, 'cart_items_partial.html')

urls.py

from django.contrib import admin
from django.urls import path
from cart.views import product_list, add_to_cart, view_cart, decrease_item, remove_item, increase_item

urlpatterns = [
    path('products/', product_list, name='product_list'),
    path('add_to_cart/<int:product_id>/', add_to_cart, name='add_to_cart')
]

templates/product_list.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Product page</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="">
        <script src="https://cdn.tailwindcss.com"></script>
        <script src="https://unpkg.com/[email protected]/dist/htmx.js"></script>
    </head>
    <body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}' class="mx-auto w-4/5 grid grid-cols-2 gap-5">
        <div>
        {% for product in products %}
            <h3>{{ product.name }}</h3>
            <p>Price: ${{ product.price }}</p>
            <button hx-post="{% url 'add_to_cart' product.id %}" hx-target="#cart" hx-swap="innerHTML">Add to Cart</button>
            <hr>
        {% endfor %}
        </div>
        
        <!-- Cart -->
        <div class="bg-blue-200 py-10 pl-5 rounded-xl">
            <h2>Your Cart</h2>
            <p>Total Items: {{ total_items_in_cart }}</p>
            <div id="cart">
                {% include "cart_items_partial.html" %}
            </div>
            <p>Total: ${{ total_price }}</p>
            <a href="{% url 'view_cart' %}">View Cart</a>
        </div>
    </body>
</html>

templates/cart_items_partial.html

{% for item in cart_items %}
<div class="bg-red-200 rounded-xl my-2 mr-2">
    <p>{{ item.product.name }} ({{ item.quantity }} x {{ item.product.price }}) = {{ item.subtotal }}</p>
</div>
{% endfor %}

when not using htmx and substitute button with <a href="{% url 'add_to_cart' product.id %}"> Add to Cart</a>

and in views.py add to cart function: return redirect('product_list')

everithing work just fine

Can you please help me implement HTMX to this project?

Thanks.

I tried code above with different hx-swap values like beforeend or outerHTML .

I expect the add to cart function to work like without HTMX but with no refresh of the page.

0

There are 0 best solutions below