Django购物车模型实现商品数量:视图渲染Entry对象疑难
嘿,看起来你已经搭好了购物车的核心模型框架,只是在模板渲染商品条目这块卡壳了对吧?别担心,咱们一步步来解决这个问题~
先修正模型里的几个小bug(避免后续踩坑)
首先看你的Entry模型和信号函数里有几个不匹配的地方,先调整一下:
class Entry(models.Model): product = models.ForeignKey(Product, null=True) # 把原来的eCart改成cart,字段名更直观,同时添加related_name方便反向查询 cart = models.ForeignKey(Cart, null=True, related_name='entries') quantity = models.PositiveIntegerField() @receiver(post_save, sender=Entry) def update_cart(sender, instance, **kwargs): # 修正之前的instance.cart(原来字段是eCart会报错),同时优化数量计算逻辑 # 重新计算购物车总数量,避免重复保存时重复累加 total_quantity = instance.cart.entries.aggregate(total=models.Sum('quantity'))['total'] or 0 instance.cart.count = total_quantity # 计算购物车小计和总价 instance.cart.subtotal = sum(entry.quantity * entry.product.price for entry in instance.cart.entries.all()) instance.cart.total = instance.cart.subtotal # 若有运费可在这里添加逻辑 instance.cart.save()
修复视图里的遗漏代码
你的cart_update函数里漏了获取商品对象的逻辑,补上后才能正确创建Entry:
def cart_update(request): product_id = request.POST.get('product_id') quantity_input= request.POST.get('quantity-field') if product_id is not None: cart_obj, new_obj = Cart.objects.new_or_get(request) # 先获取对应的商品对象 product_obj = Product.objects.get(id=product_id) # 创建Entry时使用修正后的cart外键字段 Entry.objects.create(cart=cart_obj, product=product_obj, quantity=quantity_input) # 移除多余的多对多添加逻辑(Entry已经能管理商品和数量,不需要再用products字段) # cart_obj.products.add(product_obj) # 从Entry中计算总商品数量,更新session total_items = cart_obj.entries.aggregate(total=models.Sum('quantity'))['total'] or 0 request.session['cart_items'] = total_items return redirect("carts:home")
模板渲染Entry对象的核心方法
其实你不需要额外传Entry对象到模板!因为Cart和Entry是关联的,利用Django的反向关联关系,直接在模板里通过cart对象就能获取所有关联的Entry:
比如在carts/home.html里这样写:
<h2>我的购物车</h2> {% if cart.entries.all %} <div class="cart-items"> {% for entry in cart.entries.all %} <div class="cart-item"> <span>{{ entry.product.name }}</span> <span>数量: {{ entry.quantity }}</span> <span>单价: {{ entry.product.price }}元</span> <span>小计: {{ entry.quantity|mul:entry.product.price }}元</span> </div> {% endfor %} </div> <div class="cart-summary"> <p>总商品数: {{ cart.count }}</p> <p>总价: {{ cart.total }}元</p> </div> {% else %} <p>购物车还是空的,快去逛逛吧~</p> {% endif %}
注:如果需要在模板里做乘法运算,需要先在项目中注册一个乘法过滤器,或者在视图里提前计算好每个条目的小计再传入模板。
可选:单独把Entries传入上下文
如果你觉得模板里写cart.entries.all不够直观,也可以在视图里单独取出Entries传到上下文:
def cart_home(request): cart_obj, new_obj = Cart.objects.new_or_get(request) # 取出当前购物车的所有条目 cart_entries = cart_obj.entries.all() return render(request, "carts/home.html",{"cart":cart_obj, "entries": cart_entries})
然后模板里直接用{% for entry in entries %}循环即可,效果和上面一致。
内容的提问来源于stack exchange,提问作者Tobstar
相关产品推荐
相关产品推荐

