使用JS与DRF实现购物车数量追加时重复创建购物车求助
问题根源分析
- 前端每次点击按钮都会调用
createCart发起POST请求新建购物车,完全没有尝试复用用户已有的购物车 - 后端
Cart模型未与用户关联,无法识别当前登录用户对应的购物车,导致每次创建都是全新的独立购物车
解决方案
后端修改步骤
1. 给Cart模型添加用户关联
先在models.py中给购物车模型添加用户外键,建立用户与购物车的绑定关系:
# models.py import uuid from django.contrib.auth import get_user_model from django.db import models User = get_user_model() class Cart(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) # 保留原有其他字段... class CartItem(models.Model): cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name='items') product = models.ForeignKey(Product, on_delete=models.CASCADE) quantity = models.PositiveIntegerField(default=1) # 保留原有其他字段...
执行数据库迁移:
python manage.py makemigrations python manage.py migrate
2. 修改CartViewSet,自动关联用户并提供获取当前用户购物车的接口
更新视图集,让创建购物车时自动绑定当前用户,同时新增接口用于获取用户已有的购物车:
from rest_framework import viewsets, mixins from rest_framework.decorators import action from rest_framework.response import Response from .models import Cart, CartItem from .serializers import CartSerializer, AddCartItemSerializer class CartViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet): queryset = Cart.objects.prefetch_related('items__product').all() serializer_class = CartSerializer def perform_create(self, serializer): # 创建购物车时自动绑定当前登录用户 serializer.save(user=self.request.user) @action(detail=False, methods=['get']) def current(self, request): # 获取当前用户的购物车,不存在则自动创建 cart, created = Cart.objects.get_or_create(user=request.user) serializer = self.get_serializer(cart) return Response(serializer.data)
前端修改步骤
1. 重构点击事件逻辑,先获取现有购物车再操作
不再每次点击都创建新购物车,改为先请求用户已有购物车,再添加/修改商品:
const updateBtns = document.querySelectorAll('.update-cart'); const user = '{{request.user}}'; for(let i = 0; i < updateBtns.length; i++) { updateBtns[i].addEventListener('click', function(){ event.preventDefault(); const productId = this.dataset.product; const action = this.dataset.action; // 先获取/创建用户购物车,再操作商品 handleCartOperation(productId, action); // 保留前端cookie同步逻辑 addCartItem(productId, action); }); } function handleCartOperation(productId, action) { var csrftoken = getCookie('csrftoken'); // 请求当前用户的购物车 fetch(`/api/carts/current/`, { method: 'GET', headers:{ 'Content-Type':'application/json', 'X-CSRFToken':csrftoken, }, mode: 'same-origin', }) .then(res => res.json()) .then(cartData => { const cartId = cartData.id; // 根据操作类型添加/减少商品数量 const quantity = action === 'add' ? 1 : -1; // 调用添加商品接口 addItemToCart(cartId, productId, quantity); }); } function addItemToCart(cartId, productId, quantity) { var csrftoken = getCookie('csrftoken'); fetch(`/api/carts/${cartId}/items/`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrftoken, }, body: JSON.stringify({ 'product_id': productId, 'quantity': quantity }), mode: 'same-origin', }) .then(res => res.json()) .then(data => console.log('商品操作结果:', data)); } // 保留原有前端cookie购物车逻辑 function addCartItem(productId, action){ let cart = JSON.parse(document.cookie.replace(/(?:(?:^|.*;\s*)cart\s*\=\s*([^;]*).*$)|^.*$/, "$1")) || {}; if(action === 'add'){ cart[productId] = cart[productId] ? {'quantity': cart[productId].quantity + 1} : {'quantity':1}; } if(action === 'remove'){ if(cart[productId]){ cart[productId].quantity -= 1; if(cart[productId].quantity <= 0) delete cart[productId]; } } document.cookie = `cart=${JSON.stringify(cart)};domain=;path=/`; location.reload(); } // 移除原有的createCart函数
内容的提问来源于stack exchange,提问作者David Henson
相关产品推荐
相关产品推荐

