添加不同尺寸和价格的产品到购物车 |姜戈
Add products with different sizes and price to Cart | Django
我使用 session 创建购物车。我有一个产品模型和一个 Product-sizes 模型,我在其中定义了 size-title(XL 等)和产品价格。这样我就可以拥有不同尺寸和不同价格的产品。但是我的逻辑有点问题
如果我添加尺寸为 A 的 product_1,没关系......
如果我添加尺寸为 B 的 product_1 ,没关系 ...
但是当我尝试同时添加不同尺寸的相同产品时,购物车只显示第一个尺寸的价格
#shop/models.py
class ProductSizes(models.Model):
name = models.CharField(max_length=50)
price = models.IntegerField()
picture = models.ImageField(upload_to="products/%Y/%m/%d" )
class Product(models.Model):
name = models.CharField(max_length=100)
size = models.ManyToManyField(ProductSizes , blank=True , related_name="sizes" )
price = models.IntegerField()
#cart/cart.py
from django.conf import settings
from shop.models import Product
class Cart:
def __init__(self,request):
self.session = request.session
cart = self.session.get(settings.CART_SESSION_ID)
if not cart:
cart = self.session[settings.CART_SESSION_ID] = {}
self.cart = cart
# add to cart
def add(self,product,size_,quantity=1,override_quantity=False):
product_id = str(product.id)
print(product.size.name)
if product_id not in self.cart :
if size_ != None:
if size_.off_price:
self.cart[product_id] = {'quantity':0,'price':size_.off_price}
elif size_.price:
self.cart[product_id] = {'quantity':0,'price':size_.price}
else:
if product.off_price:
self.cart[product_id] = {'quantity':0,'price':product.off_price}
else:
self.cart[product_id] = {'quantity':0,'price':product.price}
if override_quantity:
self.cart[product_id]['quantity'] = quantity
else:
self.cart[product_id]['quantity'] += quantity
self.save()
def save(self):
self.session.modified = True
#remove from cart
def remove(self,product):
product_id = str(product.id)
if product_id in self.cart:
del self.cart[product_id]
self.save()
def __iter__(self):
product_ids = self.cart.keys()
products = Product.objects.filter(id__in=product_ids)
cart = self.cart.copy()
for product in products:
cart[str(product.id)]['product'] = product
for item in cart.values():
item['total_price'] = item['price'] * item['quantity']
yield item
def __len__(self):
return sum(item['quantity'] for item in self.cart.values())
def get_total_price(self):
return sum(item['price'] * item['quantity'] for item in self.cart.values())
def clear(self):
del self.session[settings.CART_SESSION_ID]
self.save()
ـــــــــــــــــ
from django.shortcuts import get_object_or_404 , redirect , render
from django.views.decorators.http import require_POST
from .cart import Cart
from shop.models import Product, ProductSizes
from .forms import CartAddProductForm
@require_POST
def cart_add(request , product_id , size):
cart = Cart(request)
product = Product.objects.get(id=product_id)
if size != 0:
size_ = product.size.get(id=size)
else:
size_ = None
form = CartAddProductForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
cart.add(product=product , quantity=cd['quantity'] ,size_=size_, override_quantity=cd['override'] )
return redirect("home")
@require_POST
def cart_remove(request , product_id):
cart = Cart(request)
product = get_object_or_404(Product,id=product_id)
cart.remove(product=product)
return redirect("cart.detail")
def cart_detail(request):
cart = Cart(request)
for item in cart:
item['update_quantity_form'] = CartAddProductForm(initial={
'quantity':item["quantity"],
"override":True,
})
return render(request , "cart.html" , {"cart":cart})
#cart/forms.py & urls
from django import forms
PRODUCT_QUANTITY_CHOICES = [(i , str(i)) for i in range(1,21)]
class CartAddProductForm(forms.Form):
quantity = forms.TypedChoiceField(choices=PRODUCT_QUANTITY_CHOICES,coerce=int)
override = forms.BooleanField(required=False, initial=False,widget=forms.HiddenInput)
---------------
urlpatterns = [
path("" , views.cart_detail , name="cart.detail"),
path("add/<int:product_id>/<int:size>/" , views.cart_add , name="cart.add"),
path("remove/<int:product_id>/" , views.cart_remove , name="cart.remove"),
]
#html
<div class="shopping-cart-wrap">
<a href="#"> <span class="cart-total-amunt">{{cart.get_total_price}} تومان</span><i class="icon-shopping-bag2 float-left"></i><span class="cart-total">{{cart|length}}</span></a>
<ul class="mini-cart">
{% for item in cart %}
<li class="cart-item">
<div class="cart-image">
<a href="{% url 'get.single.product' item.product.slug %}"><img alt="" src="/media/{{item.product.picture}}" width="80" height="80"></a>
</div>
<div class="cart-title">
<a href="single-product.html">
<h4>{{item.product.name}}</h4>
</a>
<div class="quanti-price-wrap">
<span class="quantity">{{item.quantity}} ×</span>
<div class="price-box"><span class="new-price">{{item.price}} تومان</span></div>
</div>
<a class="{% url 'cart.remove' item.product.id %}" href="#"><i class="icon-x"></i></a>
</div>
</li>
{% endfor %}
<li class="subtotal-box">
<div class="subtotal-title">
<h3>جمع کل :</h3><span>{{cart.get_total_price}} تومان</span>
</div>
</li>
<li class="mini-cart-btns">
<div class="cart-btns">
<a href="{% url 'cart.detail' %}">مشاهده سبد</a>
<a href="{% url 'order.create' %}">پرداخت</a>
</div>
</li>
</ul>
</div>
经过 2 天的努力,我终于找到了解决方案
要添加不同尺码的产品,您必须将尺码型号 ID 而不是产品 ID 传递给会话
shop/models.py
class ProductSizes(models.Model):
name = models.CharField(max_length=50)
price = models.IntegerField()
off_price = models.IntegerField(blank=True , null=True)
picture = models.ImageField(upload_to="products/%Y/%m/%d" )
product = models.ForeignKey("Product" , on_delete=models.CASCADE )
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
picture = models.ImageField(upload_to="products/%Y/%m/%d" )
picture2 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True)
picture3 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True)
picture4 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True)
price = models.IntegerField()
available = models.BooleanField(default=True)
category = models.ForeignKey(Category ,on_delete=models.CASCADE , blank=True ,null=True )
slug = models.SlugField(max_length=100 , db_index=True , unique=True)
tags = TaggableManager(blank=True)
is_amazing = models.BooleanField(default=False)
amazing_till = models.CharField(max_length=10 , null=True , blank=True)
off_price = models.IntegerField(blank=True , null=True)
brand = models.ForeignKey(Brand ,on_delete=models.CASCADE , blank=True ,null=True )
created_at = models.DateField(auto_now_add=True)
update_at = models.DateField(auto_now=True)
def get_absolute_url(self):
return reverse('get.single.product', kwargs={'slug': self.slug})
class Meta:
ordering=("name",)
index_together = (('id' , 'slug'),)
cart/cart.py
from django.conf import settings
from shop.models import Product, ProductSizes
class Cart:
def __init__(self,request):
self.session = request.session
cart = self.session.get(settings.CART_SESSION_ID)
if not cart:
cart = self.session[settings.CART_SESSION_ID] = {}
self.cart = cart
# add to cart
def add(self,product,size_,quantity=1,override_quantity=False):
size_id = str(size_.id)
if size_id not in self.cart:
if size_.price:
self.cart[size_id] = {'quantity': 0, 'price': size_.price}
elif size_.off_price:
self.cart[size_id] = {'quantity': 0, 'price': size_.off_price}
self.cart[size_id]['quantity'] += quantity
self.save()
self.save()
def save(self):
self.session.modified = True
#remove from cart
def remove(self,size_):
product_id = str(size_.id)
if product_id in self.cart:
del self.cart[product_id]
self.save()
def __iter__(self):
sizes_ids = self.cart.keys()
products = ProductSizes.objects.filter(id__in=sizes_ids)
cart = self.cart.copy()
for size in products:
cart[str(size.id)]['size'] = size
for item in cart.values():
item['total_price'] = item['price'] * item['quantity']
yield item
def __len__(self):
return sum(item['quantity'] for item in self.cart.values())
def get_total_price(self):
return sum(item['price'] * item['quantity'] for item in self.cart.values())
def clear(self):
del self.session[settings.CART_SESSION_ID]
self.save()
cart/views.py
@require_POST
def cart_add(request , product_id , size):
cart = Cart(request)
product = Product.objects.get(id=product_id)
size_ = get_object_or_404(ProductSizes , id=size)
form = CartAddProductForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
cart.add(product=product , quantity=cd['quantity'] ,size_=size_, override_quantity=cd['override'] )
return redirect("home")
模板
{% block cart %}
<div class="shopping-cart-wrap">
<a href="#"> <span class="cart-total-amunt">{{cart.get_total_price}} تومان</span><i class="icon-shopping-bag2 float-left"></i><span class="cart-total">{{cart|length}}</span></a>
<ul class="mini-cart">
{% for item in cart %}
<li class="cart-item">
<div class="cart-image">
<a href="{% url 'get.single.product' item.size.product.slug %}"><img alt="" src="/media/{{item.size.product.picture}}" width="80" height="80"></a>
</div>
<div class="cart-title">
<a href="single-product.html">
<h4>{{item.size.name}}</h4>
</a>
<div class="quanti-price-wrap">
<span class="quantity">{{item.quantity}} ×</span>
<div class="price-box"><span class="new-price">{{item.price}} تومان</span></div>
</div>
<a class="{% url 'cart.remove' item.size.id %}" href="#"><i class="icon-x"></i></a>
</div>
</li>
{% endfor %}
<li class="subtotal-box">
<div class="subtotal-title">
<h3>جمع کل :</h3><span>{{cart.get_total_price}} تومان</span>
</div>
</li>
<li class="mini-cart-btns">
<div class="cart-btns">
<a href="{% url 'cart.detail' %}">مشاهده سبد</a>
<a href="{% url 'order.create' %}">پرداخت</a>
</div>
</li>
</ul>
</div>
{% endblock cart %}
我使用 session 创建购物车。我有一个产品模型和一个 Product-sizes 模型,我在其中定义了 size-title(XL 等)和产品价格。这样我就可以拥有不同尺寸和不同价格的产品。但是我的逻辑有点问题
如果我添加尺寸为 A 的 product_1,没关系......
如果我添加尺寸为 B 的 product_1 ,没关系 ...
但是当我尝试同时添加不同尺寸的相同产品时,购物车只显示第一个尺寸的价格
#shop/models.py
class ProductSizes(models.Model):
name = models.CharField(max_length=50)
price = models.IntegerField()
picture = models.ImageField(upload_to="products/%Y/%m/%d" )
class Product(models.Model):
name = models.CharField(max_length=100)
size = models.ManyToManyField(ProductSizes , blank=True , related_name="sizes" )
price = models.IntegerField()
#cart/cart.py
from django.conf import settings
from shop.models import Product
class Cart:
def __init__(self,request):
self.session = request.session
cart = self.session.get(settings.CART_SESSION_ID)
if not cart:
cart = self.session[settings.CART_SESSION_ID] = {}
self.cart = cart
# add to cart
def add(self,product,size_,quantity=1,override_quantity=False):
product_id = str(product.id)
print(product.size.name)
if product_id not in self.cart :
if size_ != None:
if size_.off_price:
self.cart[product_id] = {'quantity':0,'price':size_.off_price}
elif size_.price:
self.cart[product_id] = {'quantity':0,'price':size_.price}
else:
if product.off_price:
self.cart[product_id] = {'quantity':0,'price':product.off_price}
else:
self.cart[product_id] = {'quantity':0,'price':product.price}
if override_quantity:
self.cart[product_id]['quantity'] = quantity
else:
self.cart[product_id]['quantity'] += quantity
self.save()
def save(self):
self.session.modified = True
#remove from cart
def remove(self,product):
product_id = str(product.id)
if product_id in self.cart:
del self.cart[product_id]
self.save()
def __iter__(self):
product_ids = self.cart.keys()
products = Product.objects.filter(id__in=product_ids)
cart = self.cart.copy()
for product in products:
cart[str(product.id)]['product'] = product
for item in cart.values():
item['total_price'] = item['price'] * item['quantity']
yield item
def __len__(self):
return sum(item['quantity'] for item in self.cart.values())
def get_total_price(self):
return sum(item['price'] * item['quantity'] for item in self.cart.values())
def clear(self):
del self.session[settings.CART_SESSION_ID]
self.save()
ـــــــــــــــــ
from django.shortcuts import get_object_or_404 , redirect , render
from django.views.decorators.http import require_POST
from .cart import Cart
from shop.models import Product, ProductSizes
from .forms import CartAddProductForm
@require_POST
def cart_add(request , product_id , size):
cart = Cart(request)
product = Product.objects.get(id=product_id)
if size != 0:
size_ = product.size.get(id=size)
else:
size_ = None
form = CartAddProductForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
cart.add(product=product , quantity=cd['quantity'] ,size_=size_, override_quantity=cd['override'] )
return redirect("home")
@require_POST
def cart_remove(request , product_id):
cart = Cart(request)
product = get_object_or_404(Product,id=product_id)
cart.remove(product=product)
return redirect("cart.detail")
def cart_detail(request):
cart = Cart(request)
for item in cart:
item['update_quantity_form'] = CartAddProductForm(initial={
'quantity':item["quantity"],
"override":True,
})
return render(request , "cart.html" , {"cart":cart})
#cart/forms.py & urls
from django import forms
PRODUCT_QUANTITY_CHOICES = [(i , str(i)) for i in range(1,21)]
class CartAddProductForm(forms.Form):
quantity = forms.TypedChoiceField(choices=PRODUCT_QUANTITY_CHOICES,coerce=int)
override = forms.BooleanField(required=False, initial=False,widget=forms.HiddenInput)
---------------
urlpatterns = [
path("" , views.cart_detail , name="cart.detail"),
path("add/<int:product_id>/<int:size>/" , views.cart_add , name="cart.add"),
path("remove/<int:product_id>/" , views.cart_remove , name="cart.remove"),
]
#html
<div class="shopping-cart-wrap">
<a href="#"> <span class="cart-total-amunt">{{cart.get_total_price}} تومان</span><i class="icon-shopping-bag2 float-left"></i><span class="cart-total">{{cart|length}}</span></a>
<ul class="mini-cart">
{% for item in cart %}
<li class="cart-item">
<div class="cart-image">
<a href="{% url 'get.single.product' item.product.slug %}"><img alt="" src="/media/{{item.product.picture}}" width="80" height="80"></a>
</div>
<div class="cart-title">
<a href="single-product.html">
<h4>{{item.product.name}}</h4>
</a>
<div class="quanti-price-wrap">
<span class="quantity">{{item.quantity}} ×</span>
<div class="price-box"><span class="new-price">{{item.price}} تومان</span></div>
</div>
<a class="{% url 'cart.remove' item.product.id %}" href="#"><i class="icon-x"></i></a>
</div>
</li>
{% endfor %}
<li class="subtotal-box">
<div class="subtotal-title">
<h3>جمع کل :</h3><span>{{cart.get_total_price}} تومان</span>
</div>
</li>
<li class="mini-cart-btns">
<div class="cart-btns">
<a href="{% url 'cart.detail' %}">مشاهده سبد</a>
<a href="{% url 'order.create' %}">پرداخت</a>
</div>
</li>
</ul>
</div>
经过 2 天的努力,我终于找到了解决方案
要添加不同尺码的产品,您必须将尺码型号 ID 而不是产品 ID 传递给会话
shop/models.py
class ProductSizes(models.Model):
name = models.CharField(max_length=50)
price = models.IntegerField()
off_price = models.IntegerField(blank=True , null=True)
picture = models.ImageField(upload_to="products/%Y/%m/%d" )
product = models.ForeignKey("Product" , on_delete=models.CASCADE )
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
picture = models.ImageField(upload_to="products/%Y/%m/%d" )
picture2 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True)
picture3 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True)
picture4 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True)
price = models.IntegerField()
available = models.BooleanField(default=True)
category = models.ForeignKey(Category ,on_delete=models.CASCADE , blank=True ,null=True )
slug = models.SlugField(max_length=100 , db_index=True , unique=True)
tags = TaggableManager(blank=True)
is_amazing = models.BooleanField(default=False)
amazing_till = models.CharField(max_length=10 , null=True , blank=True)
off_price = models.IntegerField(blank=True , null=True)
brand = models.ForeignKey(Brand ,on_delete=models.CASCADE , blank=True ,null=True )
created_at = models.DateField(auto_now_add=True)
update_at = models.DateField(auto_now=True)
def get_absolute_url(self):
return reverse('get.single.product', kwargs={'slug': self.slug})
class Meta:
ordering=("name",)
index_together = (('id' , 'slug'),)
cart/cart.py
from django.conf import settings
from shop.models import Product, ProductSizes
class Cart:
def __init__(self,request):
self.session = request.session
cart = self.session.get(settings.CART_SESSION_ID)
if not cart:
cart = self.session[settings.CART_SESSION_ID] = {}
self.cart = cart
# add to cart
def add(self,product,size_,quantity=1,override_quantity=False):
size_id = str(size_.id)
if size_id not in self.cart:
if size_.price:
self.cart[size_id] = {'quantity': 0, 'price': size_.price}
elif size_.off_price:
self.cart[size_id] = {'quantity': 0, 'price': size_.off_price}
self.cart[size_id]['quantity'] += quantity
self.save()
self.save()
def save(self):
self.session.modified = True
#remove from cart
def remove(self,size_):
product_id = str(size_.id)
if product_id in self.cart:
del self.cart[product_id]
self.save()
def __iter__(self):
sizes_ids = self.cart.keys()
products = ProductSizes.objects.filter(id__in=sizes_ids)
cart = self.cart.copy()
for size in products:
cart[str(size.id)]['size'] = size
for item in cart.values():
item['total_price'] = item['price'] * item['quantity']
yield item
def __len__(self):
return sum(item['quantity'] for item in self.cart.values())
def get_total_price(self):
return sum(item['price'] * item['quantity'] for item in self.cart.values())
def clear(self):
del self.session[settings.CART_SESSION_ID]
self.save()
cart/views.py
@require_POST
def cart_add(request , product_id , size):
cart = Cart(request)
product = Product.objects.get(id=product_id)
size_ = get_object_or_404(ProductSizes , id=size)
form = CartAddProductForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
cart.add(product=product , quantity=cd['quantity'] ,size_=size_, override_quantity=cd['override'] )
return redirect("home")
模板
{% block cart %}
<div class="shopping-cart-wrap">
<a href="#"> <span class="cart-total-amunt">{{cart.get_total_price}} تومان</span><i class="icon-shopping-bag2 float-left"></i><span class="cart-total">{{cart|length}}</span></a>
<ul class="mini-cart">
{% for item in cart %}
<li class="cart-item">
<div class="cart-image">
<a href="{% url 'get.single.product' item.size.product.slug %}"><img alt="" src="/media/{{item.size.product.picture}}" width="80" height="80"></a>
</div>
<div class="cart-title">
<a href="single-product.html">
<h4>{{item.size.name}}</h4>
</a>
<div class="quanti-price-wrap">
<span class="quantity">{{item.quantity}} ×</span>
<div class="price-box"><span class="new-price">{{item.price}} تومان</span></div>
</div>
<a class="{% url 'cart.remove' item.size.id %}" href="#"><i class="icon-x"></i></a>
</div>
</li>
{% endfor %}
<li class="subtotal-box">
<div class="subtotal-title">
<h3>جمع کل :</h3><span>{{cart.get_total_price}} تومان</span>
</div>
</li>
<li class="mini-cart-btns">
<div class="cart-btns">
<a href="{% url 'cart.detail' %}">مشاهده سبد</a>
<a href="{% url 'order.create' %}">پرداخت</a>
</div>
</li>
</ul>
</div>
{% endblock cart %}