In my cart i can add same product with different size and color.
but randomly when i want to to add same product with different size and color i have this error in my cart iter function.
i’ve tracked the process in debugger and found that it somehow traped in my Product model str method and finally this error raise.
models:
<code>from django.db import models
from django.urls import reverse
from django.conf import settings
from colorfield.fields import ColorField
class Product(models.Model):
(GENDER_FEMALE, 'Female'),
name = models.CharField(max_length=200)
category = models.CharField(max_length=200)
gender = models.CharField(choices=GENDER_CHOICE, max_length=1)
sizes = models.ManyToManyField(to="store.Size", related_name="sizes")
slug = models.SlugField(unique=True, allow_unicode=True, db_collation='utf8_persian_ci')
price = models.PositiveIntegerField()
description = models.TextField()
inventory = models.IntegerField()
datetime_created = models.DateTimeField(auto_now_add=True)
datetime_modified = models.DateTimeField(auto_now=True)
discounts = models.IntegerField(default=0)
available_colors = models.ManyToManyField(to="store.Color", related_name="colors")
status = models.BooleanField(default=True)
def get_absolute_url(self):
return reverse("product_detail", kwargs={"slug": self.slug})
class Size(models.Model):
size = models.CharField(max_length=2)
class Color(models.Model):
name = models.CharField(max_length=200)
class Picture(models.Model):
picture = models.ImageField(upload_to=f'static/store/images/')
product = models.ForeignKey(Product, default=None, related_name='images', on_delete=models.PROTECT)
<code>from django.db import models
from django.urls import reverse
from django.conf import settings
from colorfield.fields import ColorField
class Product(models.Model):
GENDER_MALE = 'm'
GENDER_FEMALE = 'f'
GENDER_BOTH = 'b'
GENDER_CHOICE = [
(GENDER_MALE, 'Male'),
(GENDER_FEMALE, 'Female'),
(GENDER_BOTH, 'Both')
]
name = models.CharField(max_length=200)
category = models.CharField(max_length=200)
gender = models.CharField(choices=GENDER_CHOICE, max_length=1)
sizes = models.ManyToManyField(to="store.Size", related_name="sizes")
slug = models.SlugField(unique=True, allow_unicode=True, db_collation='utf8_persian_ci')
price = models.PositiveIntegerField()
description = models.TextField()
inventory = models.IntegerField()
datetime_created = models.DateTimeField(auto_now_add=True)
datetime_modified = models.DateTimeField(auto_now=True)
discounts = models.IntegerField(default=0)
available_colors = models.ManyToManyField(to="store.Color", related_name="colors")
status = models.BooleanField(default=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("product_detail", kwargs={"slug": self.slug})
class Size(models.Model):
size = models.CharField(max_length=2)
def __str__(self):
return self.size
class Color(models.Model):
color = ColorField()
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Picture(models.Model):
picture = models.ImageField(upload_to=f'static/store/images/')
product = models.ForeignKey(Product, default=None, related_name='images', on_delete=models.PROTECT)
def __str__(self):
return self.picture.url
</code>
from django.db import models
from django.urls import reverse
from django.conf import settings
from colorfield.fields import ColorField
class Product(models.Model):
GENDER_MALE = 'm'
GENDER_FEMALE = 'f'
GENDER_BOTH = 'b'
GENDER_CHOICE = [
(GENDER_MALE, 'Male'),
(GENDER_FEMALE, 'Female'),
(GENDER_BOTH, 'Both')
]
name = models.CharField(max_length=200)
category = models.CharField(max_length=200)
gender = models.CharField(choices=GENDER_CHOICE, max_length=1)
sizes = models.ManyToManyField(to="store.Size", related_name="sizes")
slug = models.SlugField(unique=True, allow_unicode=True, db_collation='utf8_persian_ci')
price = models.PositiveIntegerField()
description = models.TextField()
inventory = models.IntegerField()
datetime_created = models.DateTimeField(auto_now_add=True)
datetime_modified = models.DateTimeField(auto_now=True)
discounts = models.IntegerField(default=0)
available_colors = models.ManyToManyField(to="store.Color", related_name="colors")
status = models.BooleanField(default=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("product_detail", kwargs={"slug": self.slug})
class Size(models.Model):
size = models.CharField(max_length=2)
def __str__(self):
return self.size
class Color(models.Model):
color = ColorField()
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Picture(models.Model):
picture = models.ImageField(upload_to=f'static/store/images/')
product = models.ForeignKey(Product, default=None, related_name='images', on_delete=models.PROTECT)
def __str__(self):
return self.picture.url
views:
<code>def cart_detail_view(request):
colors = Color.objects.all()
item['product_update_quantity_form'] = AddProductToCartForm(initial={
return render(request, 'products/cart_detail.html', {'cart': cart, 'colors': colors})
def add_to_cart_view(request, pk):
product = get_object_or_404(Product, pk=pk)
form = AddProductToCartForm(request.POST)
cleaned_data = form.cleaned_data
size = cleaned_data['size']
color = cleaned_data['color']
quantity = (cleaned_data['quantity'])
replace_current_quantity = cleaned_data['inplace']
cart.add(product, size, color, quantity, replace_current_quantity)
return redirect('cart_detail')
def remove_item_from_cart(request, cart_item):
return redirect('cart_detail')
return redirect('product_list')
<code>def cart_detail_view(request):
cart = Cart(request)
colors = Color.objects.all()
for item in cart:
item['product_update_quantity_form'] = AddProductToCartForm(initial={
'inplace': True,
})
return render(request, 'products/cart_detail.html', {'cart': cart, 'colors': colors})
def add_to_cart_view(request, pk):
cart = Cart(request)
product = get_object_or_404(Product, pk=pk)
form = AddProductToCartForm(request.POST)
print(request.POST)
if form.is_valid():
cleaned_data = form.cleaned_data
size = cleaned_data['size']
color = cleaned_data['color']
quantity = (cleaned_data['quantity'])
replace_current_quantity = cleaned_data['inplace']
cart.add(product, size, color, quantity, replace_current_quantity)
return redirect('cart_detail')
def remove_item_from_cart(request, cart_item):
cart = Cart(request)
cart.remove(cart_item)
return redirect('cart_detail')
@require_POST
def clear_cart(request):
cart = Cart(request)
if len(cart) != 0:
cart.clear()
return redirect('product_list')
</code>
def cart_detail_view(request):
cart = Cart(request)
colors = Color.objects.all()
for item in cart:
item['product_update_quantity_form'] = AddProductToCartForm(initial={
'inplace': True,
})
return render(request, 'products/cart_detail.html', {'cart': cart, 'colors': colors})
def add_to_cart_view(request, pk):
cart = Cart(request)
product = get_object_or_404(Product, pk=pk)
form = AddProductToCartForm(request.POST)
print(request.POST)
if form.is_valid():
cleaned_data = form.cleaned_data
size = cleaned_data['size']
color = cleaned_data['color']
quantity = (cleaned_data['quantity'])
replace_current_quantity = cleaned_data['inplace']
cart.add(product, size, color, quantity, replace_current_quantity)
return redirect('cart_detail')
def remove_item_from_cart(request, cart_item):
cart = Cart(request)
cart.remove(cart_item)
return redirect('cart_detail')
@require_POST
def clear_cart(request):
cart = Cart(request)
if len(cart) != 0:
cart.clear()
return redirect('product_list')
cart.py:
<code>from .models import Product
def __init__(self, request):
self.session = request.session
cart = self.session.get('cart')
cart = self.session['cart'] = {}
def add(self, product, size, color, quantity=1, replace_current_quantity=False):
Add a product to the cart
for item in self.cart.items():
if item[1]['product_id'] == product.id and item[1]['size'] == size and item[1]['color'] == color:
if replace_current_quantity:
item[1]['quantity'] = quantity
item[1]['quantity'] += quantity
keys = list(self.cart.keys())
cart_item = str(int(cart_item) + 1)
self.cart[cart_item] = {'product_id': product.id}
self.cart[cart_item]['size'] = size
self.cart[cart_item]['color'] = color
self.cart[cart_item]['quantity'] = quantity
def remove(self, cart_item):
cart_item = str(cart_item)
Remove a product from the cart
if cart_item in self.cart.keys():
Mark session as modified to save changes
self.session.modified = True
product_ids = [value['product_id'] for value in self.cart.values()]
products = Product.objects.filter(id__in=product_ids)
for index,product in enumerate(products):
cart[str(keys[index])]['product_obj'] = product
cart[str(keys[index])]['cart_item'] = keys[index]
for item in cart.values():
item['total_price'] = item['product_obj'].price * item['quantity']
def get_total_price(self):
return sum(item['product_obj'].price * item['quantity'] for item in self.cart.values())
<code>from .models import Product
class Cart:
def __init__(self, request):
"""
Initialize the cart
"""
self.request = request
self.session = request.session
cart = self.session.get('cart')
if not cart:
cart = self.session['cart'] = {}
self.cart = cart
def add(self, product, size, color, quantity=1, replace_current_quantity=False):
"""
Add a product to the cart
"""
cart_item = '1'
flag = True
for item in self.cart.items():
if item[1]['product_id'] == product.id and item[1]['size'] == size and item[1]['color'] == color:
if replace_current_quantity:
item[1]['quantity'] = quantity
else:
item[1]['quantity'] += quantity
flag = False
keys = list(self.cart.keys())
if flag:
while flag:
if cart_item in keys:
cart_item = str(int(cart_item) + 1)
continue
flag = False
self.cart[cart_item] = {'product_id': product.id}
self.cart[cart_item]['size'] = size
self.cart[cart_item]['color'] = color
self.cart[cart_item]['quantity'] = quantity
self.save()
def remove(self, cart_item):
cart_item = str(cart_item)
"""
Remove a product from the cart
"""
if cart_item in self.cart.keys():
del self.cart[cart_item]
self.save()
def save(self):
"""
Mark session as modified to save changes
"""
self.session.modified = True
def __iter__(self):
product_ids = [value['product_id'] for value in self.cart.values()]
products = Product.objects.filter(id__in=product_ids)
cart = self.cart.copy()
keys = list(cart.keys())
for index,product in enumerate(products):
cart[str(keys[index])]['product_obj'] = product
cart[str(keys[index])]['cart_item'] = keys[index]
for item in cart.values():
item['total_price'] = item['product_obj'].price * item['quantity']
yield item
def __len__(self):
return len(self.cart)
def clear(self):
del self.session['cart']
self.save()
def get_total_price(self):
return sum(item['product_obj'].price * item['quantity'] for item in self.cart.values())
</code>
from .models import Product
class Cart:
def __init__(self, request):
"""
Initialize the cart
"""
self.request = request
self.session = request.session
cart = self.session.get('cart')
if not cart:
cart = self.session['cart'] = {}
self.cart = cart
def add(self, product, size, color, quantity=1, replace_current_quantity=False):
"""
Add a product to the cart
"""
cart_item = '1'
flag = True
for item in self.cart.items():
if item[1]['product_id'] == product.id and item[1]['size'] == size and item[1]['color'] == color:
if replace_current_quantity:
item[1]['quantity'] = quantity
else:
item[1]['quantity'] += quantity
flag = False
keys = list(self.cart.keys())
if flag:
while flag:
if cart_item in keys:
cart_item = str(int(cart_item) + 1)
continue
flag = False
self.cart[cart_item] = {'product_id': product.id}
self.cart[cart_item]['size'] = size
self.cart[cart_item]['color'] = color
self.cart[cart_item]['quantity'] = quantity
self.save()
def remove(self, cart_item):
cart_item = str(cart_item)
"""
Remove a product from the cart
"""
if cart_item in self.cart.keys():
del self.cart[cart_item]
self.save()
def save(self):
"""
Mark session as modified to save changes
"""
self.session.modified = True
def __iter__(self):
product_ids = [value['product_id'] for value in self.cart.values()]
products = Product.objects.filter(id__in=product_ids)
cart = self.cart.copy()
keys = list(cart.keys())
for index,product in enumerate(products):
cart[str(keys[index])]['product_obj'] = product
cart[str(keys[index])]['cart_item'] = keys[index]
for item in cart.values():
item['total_price'] = item['product_obj'].price * item['quantity']
yield item
def __len__(self):
return len(self.cart)
def clear(self):
del self.session['cart']
self.save()
def get_total_price(self):
return sum(item['product_obj'].price * item['quantity'] for item in self.cart.values())
urls:
path('products/', views.ProductListView.as_view(), name='product_list'),
path("products/<slug>/", views.ProductDetailView.as_view(), name='product_detail'),
path("products/<slug>/comment", views.CommentView.as_view(), name='comment_create'),
path('accounts/profile/', views.profile_view, name='account_profile'),
path('cart/', views.cart_detail_view, name='cart_detail'),
path('cart/add/<int:pk>/', views.add_to_cart_view, name="cart_add"),
path('cart/remove/<int:cart_item>/', views.remove_item_from_cart, name='cart_remove'),
path('clear/', views.clear_cart, name='cart_clear'),
<code>
from store import views
urlpatterns = [
path('products/', views.ProductListView.as_view(), name='product_list'),
path("products/<slug>/", views.ProductDetailView.as_view(), name='product_detail'),
path("products/<slug>/comment", views.CommentView.as_view(), name='comment_create'),
path('accounts/profile/', views.profile_view, name='account_profile'),
path('cart/', views.cart_detail_view, name='cart_detail'),
path('cart/add/<int:pk>/', views.add_to_cart_view, name="cart_add"),
path('cart/remove/<int:cart_item>/', views.remove_item_from_cart, name='cart_remove'),
path('clear/', views.clear_cart, name='cart_clear'),
]
</code>
from store import views
urlpatterns = [
path('products/', views.ProductListView.as_view(), name='product_list'),
path("products/<slug>/", views.ProductDetailView.as_view(), name='product_detail'),
path("products/<slug>/comment", views.CommentView.as_view(), name='comment_create'),
path('accounts/profile/', views.profile_view, name='account_profile'),
path('cart/', views.cart_detail_view, name='cart_detail'),
path('cart/add/<int:pk>/', views.add_to_cart_view, name="cart_add"),
path('cart/remove/<int:cart_item>/', views.remove_item_from_cart, name='cart_remove'),
path('clear/', views.clear_cart, name='cart_clear'),
]
forms:
<code>class AddProductToCartForm(forms.Form):
QUANTITY_CHOICES = [(i, str(i)) for i in range(1, 31)]
quantity = forms.TypedChoiceField(choices=QUANTITY_CHOICES, coerce=int,)
color = forms.CharField(max_length=20)
size = forms.CharField(max_length=20)
inplace = forms.BooleanField(required=False, widget=forms.HiddenInput)
<code>class AddProductToCartForm(forms.Form):
QUANTITY_CHOICES = [(i, str(i)) for i in range(1, 31)]
quantity = forms.TypedChoiceField(choices=QUANTITY_CHOICES, coerce=int,)
color = forms.CharField(max_length=20)
size = forms.CharField(max_length=20)
inplace = forms.BooleanField(required=False, widget=forms.HiddenInput)
</code>
class AddProductToCartForm(forms.Form):
QUANTITY_CHOICES = [(i, str(i)) for i in range(1, 31)]
quantity = forms.TypedChoiceField(choices=QUANTITY_CHOICES, coerce=int,)
color = forms.CharField(max_length=20)
size = forms.CharField(max_length=20)
inplace = forms.BooleanField(required=False, widget=forms.HiddenInput)
Traceback:
Request URL: http://127.0.0.1:8000/cart/
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'allauth.socialaccount.providers.google',
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'allauth.account.middleware.AccountMiddleware']
Traceback (most recent call last):
File "D:Djangoshoe_storevenvLibsite-packagesdjangocorehandlersexception.py", line 55, in inner
response = get_response(request)
File "D:Djangoshoe_storevenvLibsite-packagesdjangocorehandlersbase.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:Djangoshoe_storestoreviews.py", line 67, in cart_detail_view
File "D:Djangoshoe_storestorecart.py", line 81, in __iter__
item['total_price'] = item['product_obj'].price * item['quantity']
Exception Type: KeyError at /cart/
Exception Value: 'product_obj'
<code>Environment:
Request Method: GET
Request URL: http://127.0.0.1:8000/cart/
Django Version: 5.0.1
Python Version: 3.12.1
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
'widget_tweaks',
'colorfield',
'store',
'core']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'allauth.account.middleware.AccountMiddleware']
Traceback (most recent call last):
File "D:Djangoshoe_storevenvLibsite-packagesdjangocorehandlersexception.py", line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File "D:Djangoshoe_storevenvLibsite-packagesdjangocorehandlersbase.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:Djangoshoe_storestoreviews.py", line 67, in cart_detail_view
for item in cart:
^^^^^^
File "D:Djangoshoe_storestorecart.py", line 81, in __iter__
item['total_price'] = item['product_obj'].price * item['quantity']
^^^^^^^^^^^^^^^^^^^
Exception Type: KeyError at /cart/
Exception Value: 'product_obj'
</code>
Environment:
Request Method: GET
Request URL: http://127.0.0.1:8000/cart/
Django Version: 5.0.1
Python Version: 3.12.1
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
'widget_tweaks',
'colorfield',
'store',
'core']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'allauth.account.middleware.AccountMiddleware']
Traceback (most recent call last):
File "D:Djangoshoe_storevenvLibsite-packagesdjangocorehandlersexception.py", line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File "D:Djangoshoe_storevenvLibsite-packagesdjangocorehandlersbase.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:Djangoshoe_storestoreviews.py", line 67, in cart_detail_view
for item in cart:
^^^^^^
File "D:Djangoshoe_storestorecart.py", line 81, in __iter__
item['total_price'] = item['product_obj'].price * item['quantity']
^^^^^^^^^^^^^^^^^^^
Exception Type: KeyError at /cart/
Exception Value: 'product_obj'
i’ve tracked the process in debugger and found that it somehow traped in my Product model str method and finally this error raise.