I'm facing a problem with the code, a bug to be more specific, that is when I'm adding an item to the cart for the first time(with variations let's say Green and Medium), it's being added nicely. Then when I'm adding another item(let's say Blue and Small), it's also working. But when, I'm increasing the item quantity from the order_summary.html
, it's increasing the quantity of the other item not the one I clicked(if I clicked Red and Medium, Blue and Large's quantity is increased) and says : Please specify the required variations. Why is this happening? It's also worth noting that when I'm adding the same item with same variations from my single product page, then it's working fine. I think this bug is occurring because of the way my views is written. I tried to solve it myself, but I'm getting lost. Can anyone please help me out? Thanks in advance!
My models.py:
class Item(models.Model):
title = models.CharField(max_length=120)
price = models.FloatField()
class Variation(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
name = models.CharField(max_length=50) # size, color
class ItemVariation(models.Model):
variation = models.ForeignKey(Variation, on_delete=models.CASCADE)
value = models.CharField(max_length=50) # small, medium large etc
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
item_variations = models.ManyToManyField(ItemVariation)
quantity = models.IntegerField(default=1)
ordered = models.BooleanField(default=False)
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ref_code = models.CharField(max_length=20)
ordered = models.BooleanField(default=False)
items = models.ManyToManyField(OrderItem)
start_date = models.DateTimeField(auto_now_add= True)
ordered_date = models.DateTimeField()
My views.py:
@login_required
def add_to_cart(request, slug):
item = get_object_or_404(Item, slug=slug)
variations = request.POST.getlist('variations', [])
print(variations)
print(request.POST)
minimum_variation_count = Variation.objects.filter(item=item).count()
print(minimum_variation_count)
print(len(variations))
if len(variations) < minimum_variation_count:
messages.info(request, "Please specify the required variations.")
order_item_qs = OrderItem.objects.filter(
item=item,
user= request.user,
ordered=False,
)
for v in variations:
print(v)
order_item_qs = order_item_qs.filter(
item_variations__value=v
)
if order_item_qs.exists():
order_item = order_item_qs.first()
order_item.quantity += 1
# messages.success(request, "Product quantity was updated.")
order_item.save()
else:
order_item = OrderItem.objects.create(
item=item,
user= request.user,
ordered=False,
)
# order_item.item_variations.add(*variations)
item_variations_to_add = ItemVariation.objects.filter(
variation__item=item,
value__in=variations
).values_list('id', flat=True)
order_item.item_variations.add(*item_variations_to_add)
order_item.save()
order_qs = Order.objects.filter(user=request.user, ordered=False)
if order_qs.exists():
order = order_qs[0]
if not order.items.filter(item__id=order_item.id).exists():
order.items.add(order_item)
# print(request.POST.getlist('variations', None))
messages.success(request, "Product added to cart.")
return redirect("order-summary")
else:
ordered_date = timezone.now()
order = Order.objects.create(user=request.user, ordered_date=ordered_date)
order.items.add(order_item)
# print(request.POST.getlist('variations', None))
messages.success(request, "Product added to cart.")
return redirect("order-summary")
return redirect("order-summary")
@login_required
def remove_single_item_from_cart(request, slug):
item = get_object_or_404(Item, slug=slug)
variations = request.POST.getlist('variations', [])
order_qs = Order.objects.filter(
user=request.user,
ordered=False
)
if order_qs.exists():
order = order_qs[0]
# check if the order item is in the order
if order.items.filter(item__slug=item.slug).exists():
order_item = OrderItem.objects.filter(
item=item,
user=request.user,
ordered=False
)[0]
if order_item.quantity > 1:
order_item.quantity -= 1
order_item.save()
messages.info(request, "Product quantity was updated.")
else:
order.items.remove(order_item)
order_item.delete()
messages.info(request, "Product was removed from cart.")
return redirect("order-summary")
else:
messages.info(request, "Product was not in your cart")
return redirect("product", slug=slug)
else:
messages.info(request, "You do not have an active order")
return redirect("product", slug=slug)
return redirect("order-summary")
My order_summary.html (where I can increase quantity):
<th scope="row" class="border-0">
<div class="p-2">
<img src="{{ order_item.item.image_url }}" alt="" width="70" class="img-fluid rounded shadow-sm">
<div class="ml-3 d-inline-block align-middle">
<h5 class="mb-1"> <a href="{{ order_item.item.get_absolute_url }}" class="text-dark
-inline-block align-middle">{{ order_item.item.title }}</a>
{% for var in order_item.item_variations.all %}
<!-- <h6>{{ order_item.item_variations.all }}</h6> -->
<!-- <ul> -->
<!-- <li><h6>{{ var.variation.name }}: {{ var.value }}</h6></li> -->
<!-- </ul> -->
<h6>{{ var.variation.name }}: {{ var.value }}</h6>
{% endfor %}
</div>
</div>
</th>
{% if order_item.item.discount_price %}
<td class="border-0 align-middle"><strong>${{ order_item.get_total_discount_item_price }} <span class="badge badge-warning">Saving ${{ order_item.get_amount_saved }}</span></strong></td>
{% else %}
<td class="border-0 align-middle"><strong>${{ order_item.get_total_item_price }}</strong></td>
{% endif %}
<td class="border-0 align-middle"><strong>
<div class="pull-center">
<a href="{% url 'remove-single-item-from-cart' order_item.item.slug %}" class="btn mr-2"><i class="fa fa-minus"></i></a>
{{ order_item.quantity }}<a href="{% url 'add-to-cart' order_item.item.slug %}" class="btn ml-2"><i class="fa fa-plus"></i></a>
</div>
</div>
</strong></td>
<td class="border-0 align-middle"><a href="{% url 'remove-from-cart' order_item.item.slug %}" class="text-dark"><i class="fa fa-trash"></i></a></td>
</tr>
My single_product.html (I can increase my product quantity from here, and it is working correctly) :
<form class="form" method="POST" action="{{ object.get_add_to_cart_url }}">
{% csrf_token %}
{% for var in object.variation_set.all %}
<h5>Choose {{ var.name }}</h5>
<select class="form-control mb-4 col-md-4" name="variations">
{% for item in var.itemvariation_set.all %}
<option value="{{ item.value }}">{{ item.value|capfirst }}</option>
{% endfor %}
</select>
{% endfor %}
<div class="action">
<button class="btn btn-success">Add to Cart</button>
<button class="like btn btn-danger" type="button"><span class="fa fa-heart"></span></button>
</div>
</form>
My admin.py:
from django.contrib import admin
from .models import Item, Variation, ItemVariation
class ItemVariationAdmin(admin.ModelAdmin):
list_display = ['variation',
'value']
list_filter = ['variation', 'variation__item']
search_fields = ['value']
class ItemVariationInLineAdmin(admin.TabularInline):
model = ItemVariation
extra = 1
class VariationAdmin(admin.ModelAdmin):
list_display = ['item',
'name']
list_filter = ['item']
search_fields = ['name']
inlines = [ItemVariationInLineAdmin]
admin.site.register(Item)
admin.site.register(ItemVariation, ItemVariationAdmin)
admin.site.register(Variation, VariationAdmin)
My urls.py:
path('add_to_cart/<slug>/', orders_views.add_to_cart, name='add-to-cart'),
path('remove_from_cart/<slug>/', orders_views.remove_from_cart, name='remove-from-cart'),
variations
to be empty, since you aren't sending via POST request, and also aren't sending any variations input from your html form. This is why you get the "Please specify the required variations."
message. (len(variations) == 0
)variations
is empty, for v in variations
isn't doing any filtering work. So when you get to order_item_qs.first()
, you're not necessarily getting the OrderItem you expect, and may be +=1
on the wrong OrderItem.To fix:
increase_quantity
url endpoint, where you pass the OrderItem id into the view. Then you know exactly which OrderItem to increase the quantity and won't need to do any filtering to find it.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With