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'}), }
问题原因
- 表单验证失效:
ShippingAddress模型的所有字段都设置了blank=True,导致Django表单验证时允许空值提交,form.is_valid()直接返回True,即使表单完全为空。 - 未校验购物车状态:修改购物车查询逻辑后,若用户购物车为空,
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
相关产品推荐
相关产品推荐

