[Python] Django ManyToMany Relationship Not Returning First Available Size in View

Discussão em 'Python' iniciado por Stack, Março 30, 2025.

  1. Stack

    Stack Membro Participativo

    I am working on a Django e-commerce project where a product can have multiple sizes. However, I am facing an issue where, if no size is explicitly selected by the user, the system should automatically take the first available size of the product. Currently, it always returns "No Size", even though sizes exist for the product.

    Models:


    Here is my Product model:

    class Product(models.Model):
    pid = ShortUUIDField(length=10, max_length=100, prefix="prd", alphabet="abcdef")
    title = models.CharField(max_length=100, default="Apple")
    image = models.ImageField(upload_to=user_directory_path, default="product.jpg")
    price = models.DecimalField(max_digits=10, decimal_places=2, default=1.99)
    old_price = models.DecimalField(max_digits=10, decimal_places=2, default=2.99)

    size = models.ManyToManyField("Size", blank=True)

    def get_product_price_by_size(self):
    """Returns price based on the first available size if none is selected"""
    first_size = self.size.first() # Get the first available size
    if first_size:
    return self.price + first_size.price # Assuming 'price' exists in Size model
    return self.price # Default to base price if no size exists

    def __str__(self):
    return self.title


    class Size(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)

    def __str__(self):
    return self.name

    View Handling "Add to Cart" (add_to_cart_search):


    When a user clicks "Add to Cart," I want to fetch the product's size. If no size is explicitly selected, the first available size should be assigned automatically.

    def add_to_cart_search(request):
    if request.GET.get('buy_now'):
    return redirect('core:payment_getway')

    product_id = request.GET.get('pid') # Product ID
    quantity = int(request.GET.get('qty', 1)) # Default to 1
    selected_size_id = request.GET.get('sizeid') # Get selected size ID from AJAX
    size_name = "No Size"
    product_price = 0
    old_price = 0

    try:
    # Fetch product
    product = Product.objects.get(pid=product_id)
    product_price = product.price
    old_price = product.old_price

    # If user selected a size, use it; otherwise, take the first available size
    if selected_size_id and selected_size_id != "null":
    try:
    selected_size = Size.objects.get(id=selected_size_id)
    product_price = selected_size.price # Use size price
    size_name = selected_size.name
    except Size.DoesNotExist:
    pass # If size not found, keep default price
    else:
    first_size = product.size.first() # Fetch first available size
    if first_size:
    product_price = first_size.price
    size_name = first_size.name
    selected_size_id = first_size.id # Assign ID for cart

    except Product.DoesNotExist:
    return JsonResponse({"error": "Product not found"}, status=400)

    # Unique key for cart session
    product_id_size_key = f"{product_id}_{selected_size_id or 'no_size'}"

    cart_product = {
    product_id_size_key: {
    'pid': product_id,
    'title': f"Size: {size_name}",
    'image': request.GET.get('image', ''),
    'qty': quantity,
    'price': str(product_price),
    'size': selected_size_id or "no_size",
    'sizename': size_name,
    'old_price': str(old_price),
    }
    }

    # Update cart session
    if 'cart_data_obj' in request.session:
    cart_data = request.session['cart_data_obj']
    if product_id_size_key in cart_data:
    cart_data[product_id_size_key]['qty'] += quantity
    else:
    cart_data.update(cart_product)

    request.session['cart_data_obj'] = cart_data
    request.session['total_cart_items'] = len(cart_data)
    else:
    request.session['cart_data_obj'] = cart_product
    request.session['total_cart_items'] = len(cart_product)

    return JsonResponse({
    "data": request.session['cart_data_obj'],
    'totalcartitems': request.session['total_cart_items']
    })

    JavaScript (AJAX Call to Add Product to Cart):


    The JavaScript function should send the first available size if none is explicitly selected.

    $(document).ready(function () {
    function addToCartFunction() {
    let this_val = $(this);

    if (this_val.text() === "Go to Cart") {
    window.location.href = "/cart/";
    return;
    }

    let quantity = $("#product-quantity").val() || 1;
    let product_id = this_val.data("id");
    let product_pid = this_val.data("pid");
    let product_image = this_val.data("image");
    let product_title = this_val.data("title");

    let selected_size_input = $("input[name='size']:checked");
    let first_size_input = $(".size-options input:first");

    let selected_size_id = selected_size_input.length
    ? selected_size_input.val()
    : first_size_input.length
    ? first_size_input.val()
    : null;

    let selected_size = selected_size_input.length
    ? selected_size_input.siblings("label").text().trim()
    : first_size_input.length
    ? first_size_input.siblings("label").text().trim()
    : "No Size";

    console.log("Selected Size ID:", selected_size_id);
    console.log("Selected Size:", selected_size);

    $.ajax({
    url: "/add-to-cart-search/",
    data: {
    id: product_id,
    pid: product_pid,
    image: product_image,
    qty: quantity,
    title: product_title,
    sizeid: selected_size_id,
    sizename: selected_size,
    },
    dataType: "json",
    beforeSend: function () {
    console.log(" Sending request to add product...");
    },
    success: function (res) {
    this_val.html("Go to Cart");
    $(".cart-items-count").text(res.totalcartitems);
    },
    error: function (xhr) {
    console.error("❌ Error adding to cart:", xhr.responseText);
    },
    });
    }

    $(".cart-btn").on("click", addToCartFunction);
    });


    HTML:

    <button type="button" class="cart-btn"
    data-id="{{ p.id }}"
    data-pid="{{ p.pid }}"
    data-image="{{ p.image.url }}"
    data-title="{{ p.title }}">
    Add to Cart
    </button>

    Issue Summary:

    • The system should select the first available size if none is explicitly chosen.
    • The size.first() is not returning the first available size in the add_to_cart_search view.
    • Even though the product has sizes, it defaults to "No Size."
    • How can I ensure that the first available size is automatically selected in both Django and JavaScript?

    Any help or suggestions would be greatly appreciated!

    Continue reading...

Compartilhe esta Página