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

Django订单表单未校验:空表单仍跳转支付成功页问题

Django电商订单表单空提交跳转成功问题修复

问题背景

将购物车项查询从CartItem.objects.all()改为CartItem.objects.filter(user=request.user)后,出现了一个问题:即使订单表单完全为空,提交后页面仍会跳转到「支付成功」页面。核心相关代码如下:

原views.py

@login_required
def checkout(request):
    items = CartItem.objects.all()
    total_price = sum([item.product.price * item.quantity for item in items])

    if request.method == 'POST':
        form = ShippingAddressForm(request.POST)
        if form.is_valid():
            # 创建订单并关联用户
            order = Order.objects.create(customer=request.user)

            # 将购物车项关联到订单
            for item in items:
                item.order = order
                item.save()

            # 清空购物车
            items.delete()

            # 跳转到成功页面
            return redirect('success')
        else:
            messages.error(request, 'Form has errors. Please correct them.')
    else:
        form = ShippingAddressForm()

    return render(request, 'checkout.html', {'items': items, 'total_price': total_price, 'form': form})

原models.py(ShippingAddress部分)

class ShippingAddress(models.Model):
    full_name = models.CharField(max_length=200, blank=True)
    address = models.CharField(max_length=200, blank=True)
    city = models.CharField(max_length=200, blank=True)
    country = models.CharField(max_length=200, blank=True)
    zip_code = models.IntegerField(blank=True)

    def __str__(self):
        return self.full_name

原forms.py

from django import forms
from .models import ShippingAddress


class ShippingAddressForm(forms.ModelForm):
    class Meta:
        model = ShippingAddress
        fields = '__all__'
        widgets = {
            'full_name': forms.TextInput(attrs={'class': 'form-control'}),
            'address': forms.TextInput(attrs={'class': 'form-control'}),
            'city': forms.TextInput(attrs={'class': 'form-control'}),
            'country': forms.TextInput(attrs={'class': 'form-control'}),
            'zip_code': forms.TextInput(attrs={'class': 'form-control'}),
        }

问题原因

  1. 表单验证失效:ShippingAddress模型的所有字段都设置了blank=True,导致Django表单验证时允许空值提交,form.is_valid()直接返回True,即使表单完全为空。
  2. 未校验购物车状态:修改购物车查询逻辑后,若用户购物车为空,items会是一个空集合,但视图代码没有判断购物车是否有商品,仍然会创建空订单并跳转成功页面。

修复方案

1. 修正模型字段的必填性

移除ShippingAddress模型字段的blank=True,让字段默认成为必填项:

class ShippingAddress(models.Model):
    full_name = models.CharField(max_length=200)
    address = models.CharField(max_length=200)
    city = models.CharField(max_length=200)
    country = models.CharField(max_length=200)
    zip_code = models.IntegerField()

    def __str__(self):
        return self.full_name

如果需要保留模型层面的blank=True但强制表单必填,可以在forms.py中单独设置验证规则:

class ShippingAddressForm(forms.ModelForm):
    class Meta:
        model = ShippingAddress
        fields = '__all__'
        widgets = {
            'full_name': forms.TextInput(attrs={'class': 'form-control'}),
            'address': forms.TextInput(attrs={'class': 'form-control'}),
            'city': forms.TextInput(attrs={'class': 'form-control'}),
            'country': forms.TextInput(attrs={'class': 'form-control'}),
            'zip_code': forms.TextInput(attrs={'class': 'form-control'}),
        }
    
    # 强制所有字段必填
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.required = True

2. 视图中添加购物车空值校验

在处理POST请求前,先判断购物车是否有商品,为空则阻止提交并提示错误:

@login_required
def checkout(request):
    # 改为用户专属购物车查询
    items = CartItem.objects.filter(user=request.user)
    total_price = sum([item.product.price * item.quantity for item in items])

    if request.method == 'POST':
        # 先判断购物车是否为空
        if not items.exists():
            messages.error(request, '购物车为空,无法提交订单')
            return redirect('checkout')
        
        form = ShippingAddressForm(request.POST)
        if form.is_valid():
            order = Order.objects.create(customer=request.user)

            for item in items:
                item.order = order
                item.save()

            items.delete()

            return redirect('success')
        else:
            messages.error(request, '表单填写有误,请修正后提交')
    else:
        form = ShippingAddressForm()

    return render(request, 'checkout.html', {'items': items, 'total_price': total_price, 'form': form})

3. 前端错误提示优化(可选)

修正前端模板中错误提示的对应关系,确保每个字段的提示正确:

<!-- 示例:full_name字段的错误提示 -->
<div class="col-md-6 mb-3">
    <label for="{{ form.full_name.id_for_label }}">{{ form.full_name.label }}</label>
    {{ form.full_name }}
    {% if form.full_name.errors %}
        <div class="invalid-feedback d-block">
            {{ form.full_name.errors.0 }}
        </div>
    {% else %}
        <div class="invalid-feedback">
            请填写姓名
        </div>
    {% endif %}
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:28:08