python - 产品变体未反映 Django 电子商务项目中订单摘要中的更新数量
问题描述
我对订单摘要页面中的变体和与其相关的数量有疑问。
当我将 2 件商品添加到购物车时:
- 商品 X 尺寸较小 数量:1
- 商品 X 中号 数量:1
当我更改 item X size medium 的数量时,此更改反映在 item X size small 中,这是首先选择的。
变成这样:
- 项目 X 尺寸小 数量:2
- 商品 X 中号 数量:1
在订单摘要中,模板中有一个加号和一个减号来更改数量。
我最近明白了,因为模板中没有表格。将带有表单数据的 POST 请求发送到添加到购物车视图的代码不存在,因为 item_var 将始终是一个空列表,因此 order_item.variation.add(*item_var) 什么都不做。我不知道如何向此模板添加 POST 请求。
在模板中有一个“添加到购物车的 URL”,但是 URL 是通过 GET 传输的,所以 if request.method == 'POST': 之后的代码永远不会命中。此外,即使它会, add_to_cart url 知道与变化无关,因为它只会获得项目 slug。
这是模板:
<main>
<div class="container">
<div class="table-responsive text-nowrap" style="margin-top:90px">
<h2> Order Summary</h2>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Item Title</th>
<th scope="col">Price</th>
<th scope="col">Quantity</th>
<th scope="col">Size</th>
<th scope="col">Total Item Price</th>
</tr>
</thead>
<tbody>
{% for order_item in object.items.all %}
<tr>
<th scope="row">{{ forloop.counter }}</th>
<td>{{ order_item.item.title }}</td>
<td>{{ order_item.item.price }}</td>
<td>
<a href="{% url 'core:remove-single-item-from-cart' order_item.item.slug %}"><i class="fas fa-minus mr-2"></a></i>
{{ order_item.quantity }}
<a href="{% url 'core:add-to-cart' order_item.item.slug %}"><i class="fas fa-plus ml-2"></a></i>
</td>
<td>
{% if order_item.variation.all %}
{% for variation in order_item.variation.all %}
{{ variation.title|capfirst }}
{% endfor %}
{% endif %}
</td>
<td>
{% if order_item.item.discount_price %}
$ {{ order_item.get_total_discount_item_price }}
<span class="badge badge-primary" style="margin-left:10px">Saving ${{ order_item.get_amount_saved }}</span>
{% else %}
$ {{ order_item.get_total_item_price }}
{% endif %}
<a style="color:red" href="{% url 'core:remove-from-cart' order_item.item.slug %}">
<i class="fas fa-trash float-right"></i>
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan='5'>Your Cart is Empty</td>
</tr>
<tr>
<td colspan="5">
<a class='btn btn-primary float-right ml-2'href='/'>Continue Shopping</a>
</tr>
{% endfor %}
{% if object.coupon %}
<tr>
<td colspan="4"><b>Coupon</b></td>
<td><b>-${{ object.coupon.amount }}</b></td>
</tr>
{% endif %}
<tr>
<td colspan="5"><b>Sub total</b></td>
<td><b>${{ object.get_total }}</b></td>
</tr>
<tr>
<td colspan="5">Taxes</td>
<td>${{ object.get_taxes|floatformat:2 }}</td>
</tr>
{% if object.grand_total %}
<tr>
<td colspan="5"><b>Grand Total</b></td>
<td><b>${{ object.grand_total|floatformat:2 }}</b></td>
</tr>
<tr>
<td colspan="6">
<a class='btn btn-primary float-right ml-2'href='/'>Continue Shopping</a>
<a class='btn btn-warning float-right'href='/checkout/'>Proceed to Checkout</a></td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
</main>
这是views.py
class OrderSummaryView(LoginRequiredMixin, View):
def get(self, *args, **kwargs):
try:
order = Order.objects.get(user=self.request.user, ordered=False)
context = {
'object': order
}
return render(self.request, 'order_summary.html', context)
except ObjectDoesNotExist:
messages.warning(self.request, "You do not have an active order")
return redirect("/")
@login_required
def add_to_cart(request, slug):
item = get_object_or_404(Item, slug=slug)
order_item_qs = OrderItem.objects.filter(
item=item,
user=request.user,
ordered=False
)
item_var = [] # item variation
if request.method == 'POST':
for items in request.POST:
key = items
val = request.POST[key]
try:
v = Variation.objects.get(
item=item,
category__iexact=key,
title__iexact=val
)
item_var.append(v)
except:
pass
if len(item_var) > 0:
for items in item_var:
order_item_qs = order_item_qs.filter(
variation__exact=items,
)
if order_item_qs.exists():
order_item = order_item_qs.first()
order_item.quantity += 1
order_item.save()
else:
order_item = OrderItem.objects.create(
item=item,
user=request.user,
ordered=False
)
order_item.variation.add(*item_var)
order_item.save()
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 not order.items.filter(item__id=order_item.id).exists():
order.items.add(order_item)
messages.info(request, "This item quantity was updated.")
return redirect("core:order-summary")
else:
ordered_date = timezone.now()
order = Order.objects.create(
user=request.user, ordered_date=ordered_date)
order.items.add(order_item)
messages.info(request, "This item was added to cart.")
return redirect("core:order-summary")
@login_required
def remove_from_cart(request, slug):
item = get_object_or_404(Item, slug=slug)
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]
order.items.remove(order_item)
order_item.delete()
messages.info(request, "This item was removed from your cart")
return redirect("core:order-summary")
else:
messages.info(request, "This item was not in your cart")
return redirect("core:product", slug=slug)
else:
messages.info(request, "You don't have an active order")
return redirect("core:product", slug=slug)
@login_required
def remove_single_item_from_cart(request, slug):
item = get_object_or_404(Item, slug=slug)
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()
else:
order.items.remove(order_item)
messages.info(request, "This item quantity was updated")
return redirect("core:order-summary")
else:
messages.info(request, "This item was not in your cart")
return redirect("core:product", slug=slug)
else:
messages.info(request, "You do not have an active order")
return redirect("core:product", slug=slug)
这是models.py
class Item(models.Model):
title = models.CharField(max_length=100)
-------------------------------------------------------------------------
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("core:product", kwargs={
'slug': self.slug
})
def get_add_to_cart_url(self):
return reverse("core:add-to-cart", kwargs={
'slug': self.slug
})
def get_remove_from_cart_url(self):
return reverse("core:remove-from-cart", kwargs={
'slug': self.slug
})
class VariationManager(models.Manager):
def all(self):
return super(VariationManager, self).filter(active=True)
def sizes(self):
return self.all().filter(category='size')
def colors(self):
return self.all().filter(category='color')
VAR_CATEGORIES = (
('size', 'size',),
('color', 'color',),
('package', 'package'),
)
class Variation(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
category = models.CharField(
max_length=120, choices=VAR_CATEGORIES, default='size')
title = models.CharField(max_length=120)
image = models.ImageField(null=True, blank=True)
price = models.DecimalField(
decimal_places=2, max_digits=100, null=True, blank=True)
objects = VariationManager()
active = models.BooleanField(default=True)
def __str__(self):
return self.title
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
variation = models.ManyToManyField(Variation)
def __str__(self):
return f"{self.quantity} of {self.item.title}"
网址.py
app_name = 'core'
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('order-summary/', OrderSummaryView.as_view(), name='order-summary'),
path('product/<slug>/', ItemDetailView.as_view(), name='product'),
path('add-to-cart/<slug>/', add_to_cart, name='add-to-cart'),
path('remove-item-from-cart/<slug>/', remove_single_item_from_cart,
name='remove-single-item-from-cart'),
path('remove-from-cart/<slug>/', remove_from_cart, name='remove-from-cart'),
]
解决方案
当然,对于 django 来说,这两个项目都是一样的。
对此负责的线路是:
if order_item_qs.exists():
order_item = order_item_qs.first() # Here, you are always picking the first item that your filter returned, see: https://docs.djangoproject.com/en/dev/ref/models/querysets/#first
order_item.quantity += 1
order_item.save()
取自https://docs.djangoproject.com/en/dev/ref/models/querysets/#first:
第一的()¶
返回查询集匹配的第一个对象,如果没有匹配的对象,则返回 None。如果 QuerySet 没有定义排序,则查询集会自动按主键排序。这可能会影响聚合结果,如与默认排序或 order_by() 交互中所述。
然而,罪魁祸首是:
order_item_qs = OrderItem.objects.filter(
item=item,
user=request.user,
ordered=False
)
您想将变化传递给它,例如
order_item_qs = OrderItem.objects.filter(
item=item,
user=request.user,
ordered=False,
variation=variation
)
您可以考虑将尺寸添加为产品字段并根据变化创建单个产品。但是,简单地检索变化并确保只通过将正确的项目传递给 filter() 来增加正确的项目也是一种正确的方法。
推荐阅读
- javascript - React Native Fetch(uri)说网络[TypeError:网络请求失败],当我尝试检索本地图像时
- ms-access - 无法在 Access 宏中捕获 /cmd 值
- c# - 在 XML 中搜索元素
- angular - 角订阅。无法获取数据
- c - 为什么我的代码中出现分段错误?
- javascript - 500 内部服务器错误 Asp.net C# 数据表
- php - 使用 PHP 清理 GET 查询 url
- python - numpy中的多个插入,其中配对元素没有潜台词
- visual-studio-2015 - 与 VS 2015 的角度集成
- angular - 在日历的对象数组上使用 ngFor