You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django表单提交:处理未选择颜色和尺寸的异常提示问题

Django购物车表单无法获取颜色和尺寸问题修复

问题现象

开发Django项目时,设置了购物车添加表单,要求用户选择颜色和尺寸后才能添加商品,但提交表单时终端会打印No color selected和No size selected,无法正确获取用户选中的颜色与尺寸信息,且购物车仅存储商品ID,无法区分不同规格的商品。

现有代码

home.html

<form method="POST" action="{% url 'add_to_cart' products.id %}">
  <div>
    <select name="colors" class="border border-gray-200 focus:outline-none ">
      {% for color in Colors.all %}
        <option value="{{color.color}}">{{color.color|capfirst}}</option>
      {% endfor %}
    </select>
    <select name="sizes" class="border border-gray-200 focus:outline-none ">
      {% for size in Sizes.all %}
        <option value="{{ size.size }}">{{ size.size }}</option>
      {% endfor %}
    </select>
  </div>
</form>

views.py

from django.shortcuts import render,redirect
from .models import *

def home(request):
    product = Product.objects.all()
    sizes = Sizes.objects.all()
    colors = Colors.objects.all()
    return render(request , 'home.html' , {'Product':product  , 'Sizes':sizes , 'Colors':colors})


def add_to_cart(request, product_id):
    product = Product.objects.get(id=product_id)
    cart = request.session.get('cart', [])
    
    if request.method == 'POST':
        selected_color = request.POST.get('colors')
        selected_size = request.POST.get('sizes')
        cart_item = {
            'product_id': product.id,
            'color': selected_color,
            'size': selected_size,
        }
        print(cart_item['product_id'])
        
        if selected_color is not None:
            print(cart_item['color'])
        else:
            print("No color selected")
        
        if selected_size is not None:
            print(cart_item['size'])  
        else:
            print("No size selected")
    cart.append(product.id)
    request.session['cart'] = cart
    return redirect('home')


def view_cart(request):
    # Retrieve the cart from the session or create an empty cart if it doesn't exist
    cart = request.session.get('cart', [])
    # Retrieve the products in the cart based on the product IDs stored in the cart
    cart_products = Product.objects.filter(id__in=cart)
    
    # Calculate the subtotal
    subtotal = sum(product.price for product in cart_products)

    context = {
        'cart': cart_products,
        'subtotal': subtotal,
    }
    return render(request, 'cart.html', context)

def remove_from_cart(request, product_id):
    # Retrieve the cart from the session or create an empty cart if it doesn't exist
    cart = request.session.get('cart', [])

    # Remove the product with the given product_id from the cart
    if product_id in cart:
        cart.remove(product_id)
        request.session['cart'] = cart

    return redirect('cart')

models.py

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    image = models.ImageField(upload_to='products/')

    def __str__(self):
        return self.name
    
class Sizes(models.Model):
    product = models.ForeignKey(Product , on_delete=models.CASCADE)
    size = models.CharField(max_length=5)
    
    class Meta:
        verbose_name_plural = 'Sizes'
    
    def __str__(self) -> str:
        return str(self.product)
    
    
class Colors(models.Model):
    product = models.ForeignKey(Product , on_delete=models.CASCADE)
    color = models.CharField(max_length=10)
    
    class Meta:
        verbose_name_plural = 'Colors'
    
    def __str__(self) -> str:
        return str(self.product)

问题分析

  1. 表单缺少提交按钮与CSRF令牌:现有表单无提交按钮,用户无法触发提交;同时缺少Django要求的CSRF令牌,POST请求会被拦截。
  2. 下拉框数据错误:当前下拉框遍历所有商品的颜色/尺寸(Colors.all/Sizes.all),而非当前商品对应的可选规格,导致选项与商品不匹配。
  3. 购物车逻辑错误:
    • cart.append(product.id)在POST判断代码块外,无论是否提交表单都会执行,未选规格也会添加商品。
    • 购物车仅存储商品ID,无法区分同一商品的不同颜色/尺寸规格。
  4. 前端无验证:未给下拉框添加必填验证,用户可直接提交空选项。

修复方案

1. 修正home.html表单

添加提交按钮、CSRF令牌,遍历当前商品的规格选项,添加前端必填验证:

{% for product in products %}
<!-- 商品展示代码 -->
<form method="POST" action="{% url 'add_to_cart' product.id %}">
  {% csrf_token %}
  <div>
    <select name="colors" class="border border-gray-200 focus:outline-none " required>
      {% for color in product.colors_set.all %}
        <option value="{{color.color}}">{{color.color|capfirst}}</option>
      {% endfor %}
    </select>
    <select name="sizes" class="border border-gray-200 focus:outline-none " required>
      {% for size in product.sizes_set.all %}
        <option value="{{ size.size }}">{{ size.size }}</option>
      {% endfor %}
    </select>
    <button type="submit" class="mt-2">添加到购物车</button>
  </div>
</form>
{% endfor %}

2. 修正home视图函数

传递统一的变量名,无需提前查询所有规格:

def home(request):
    products = Product.objects.all()
    return render(request , 'home.html' , {'products':products})

3. 修正add_to_cart函数

调整逻辑,仅在获取有效规格时添加商品,同时存储完整规格信息:

def add_to_cart(request, product_id):
    product = Product.objects.get(id=product_id)
    cart = request.session.get('cart', [])
    
    if request.method == 'POST':
        selected_color = request.POST.get('colors')
        selected_size = request.POST.get('sizes')
        
        if selected_color and selected_size:
            cart_item = {
                'product_id': product.id,
                'color': selected_color,
                'size': selected_size,
                'name': product.name,
                'price': float(product.price),
                'image': product.image.url if product.image else ''
            }
            cart.append(cart_item)
            request.session['cart'] = cart
        else:
            print("请选择颜色和尺寸")
    
    return redirect('home')

4. 修正view_cart函数

适配新的购物车数据结构,展示带规格的商品信息:

def view_cart(request):
    cart = request.session.get('cart', [])
    subtotal = sum(item['price'] for item in cart)

    context = {
        'cart': cart,
        'subtotal': subtotal,
    }
    return render(request, 'cart.html', context)

5. 修正remove_from_cart函数

适配新数据结构,按商品ID+规格删除条目:

def remove_from_cart(request, product_id, color, size):
    cart = request.session.get('cart', [])
    cart = [item for item in cart if not (item['product_id'] == product_id and item['color'] == color and item['size'] == size)]
    request.session['cart'] = cart
    return redirect('cart')

需同步修改URL配置,传递color和size参数。

验证修复

  1. 启动项目后,每个商品的下拉框将显示对应商品的颜色/尺寸选项。
  2. 未选择规格时点击提交,浏览器会拦截并提示必填。
  3. 选择规格提交后,终端不再打印错误提示,购物车将存储包含完整规格的商品信息。
  4. 购物车页面可展示带颜色、尺寸的商品条目。

内容的提问来源于stack exchange,提问作者zep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 20:39:54