Django项目中CartAddProductForm的form.is_valid始终返回False求助
解决Django中CartAddProductForm调用is_valid()始终返回False的问题
问题现象
开发个人Django项目时,调用form.is_valid()时,CartAddProductForm始终返回False,提交商品到购物车后,购物车页面为空。打印错误信息无具体内容,输出如下:
form.is_valid = False request.POST = <QueryDict: {'sizes': ['S'], 'csrfmiddlewaretoken': ['mytoken']}> form.errors = form.non_field_errors = <bound method BaseForm.non_field_errors of <CartAddProductForm bound=False, valid=False, fields=(sizes)>> field_errors = [('Sizes', [])]
代码详情
forms.py
从数据库获取商品尺寸生成ChoiceField:
class CartAddProductForm(ModelForm): class Meta: model = Product fields = ['sizes'] def __init__(self, pk: int, *args, **kwargs) -> None: super(CartAddProductForm, self).__init__(*args, **kwargs) sizes = tuple(Product.objects.get(pk=pk).sizes) sizes_list = [] for item in sizes: sizes_list.append((item, item)) self.fields['sizes'] = forms.ChoiceField(choices=sizes_list)
views.py
product_detail视图初始化表单,add_to_cart视图处理提交请求:
product_detail视图
def product_detail(request: WSGIRequest, product_id: int, product_slug: str) -> HttpResponse: product = get_object_or_404(Product, id=product_id, slug=product_slug, available=True) categories = Category.objects.all() cart_product_form = CartAddProductForm(instance=product, pk=product_id) return render(request, 'shop/product/detail.html', {'product': product, 'categories': categories, 'cart_product_form': cart_product_form})
add_to_cart视图
@require_POST def add_to_cart(request: WSGIRequest, product_id: int) -> HttpResponseRedirect: cart = Cart(request) product = get_object_or_404(Product, id=product_id) form = CartAddProductForm(instance=product, pk=product_id) if form.is_valid(): cd = form.cleaned_data print(f'cd = {cd}') cart.add(product=product, quantity=cd['quantity'], update_quantity=cd['update']) else: print(f'form.is_valid = {form.is_valid()}') print(f'request.POST = {request.POST}') print(f'form.errors = {form.errors}') print(f'form.non_field_errors = {form.non_field_errors}') field_errors = [(field.label, field.errors) for field in form] print(f'field_errors = {field_errors}') return redirect('cart:cart_detail')
模板文件
{% extends "shop/base.html" %} <head> <meta charset="UTF-8"> <title>Detail</title> </head> <body> {% block title %} {{ product.name }} {% endblock %} {% block content %} <br> <b>{{ product.name }} </b> <br> <i>{{ product.description }} </i> <br> {{ product.price }} <br> <img src="{{ product.image.url }}" width="300" height="500"> <br> Доступные размеры: <br> {{ product.sizes }}<br> <form action="{% url "cart:add_to_cart" product.id %}" method="post"> {{ cart_product_form }} {{ form.as_p }} {% csrf_token %} <input type="submit" value="Add to cart"> </form> {% endblock %} </body>
urls.py
urlpatterns = [ re_path(r'^$', views.cart_detail, name='cart_detail'), re_path(r'^add/(?P<product_id>\d+)/$', views.add_to_cart, name='add_to_cart'), re_path(r'^remove/(?P<product_id>\d+)/$', views.cart_remove, name='cart_remove'), ]
问题根源
- 表单未绑定POST数据:
add_to_cart视图中初始化CartAddProductForm时,未传入request.POST数据,导致表单处于未绑定状态(bound=False),未绑定表单调用is_valid()会直接返回False。 - 冗余的instance参数:该表单用于接收用户选择的尺寸,无需绑定Product实例,传入
instance=product属于无效操作,可能干扰验证逻辑。 - 模板冗余代码:模板中
{{ form.as_p }}对应的变量不存在于上下文,会输出空内容,无实际作用。 - 尺寸字段转换潜在问题:若Product模型的
sizes是字符串类型(如逗号分隔),直接转tuple会将每个字符拆分为选项,导致选项不匹配提交值。
解决方案
1. 修改add_to_cart视图,绑定POST数据
调整表单初始化代码,传入request.POST并移除冗余的instance参数:
@require_POST def add_to_cart(request: WSGIRequest, product_id: int) -> HttpResponseRedirect: cart = Cart(request) product = get_object_or_404(Product, id=product_id) # 绑定POST数据,仅传入必要的pk参数 form = CartAddProductForm(pk=product_id, data=request.POST) if form.is_valid(): cd = form.cleaned_data print(f'cd = {cd}') # 若表单未定义quantity和update字段,需添加对应字段或调整逻辑 cart.add(product=product, quantity=cd.get('quantity', 1), update_quantity=cd.get('update', False)) else: print(f'form.is_valid = {form.is_valid()}') print(f'request.POST = {request.POST}') print(f'form.errors = {form.errors}') print(f'form.non_field_errors() = {form.non_field_errors()}') # 调用方法而非引用 field_errors = [(field.label, field.errors) for field in form] print(f'field_errors = {field_errors}') return redirect('cart:cart_detail')
2. 清理模板冗余代码
移除模板中多余的{{ form.as_p }}:
<form action="{% url "cart:add_to_cart" product.id %}" method="post"> {{ cart_product_form }} {% csrf_token %} <input type="submit" value="Add to cart"> </form>
3. 修正尺寸字段转换逻辑
如果Product模型的sizes是逗号分隔的字符串,修改forms.py中的转换代码:
def __init__(self, pk: int, *args, **kwargs) -> None: super(CartAddProductForm, self).__init__(*args, **kwargs) # 处理逗号分隔的尺寸字符串,如"S,M,L" sizes_str = Product.objects.get(pk=pk).sizes sizes = sizes_str.split(',') sizes_list = [(item.strip(), item.strip()) for item in sizes] self.fields['sizes'] = forms.ChoiceField(choices=sizes_list)
4. 调整product_detail视图的表单初始化
移除冗余的instance参数:
cart_product_form = CartAddProductForm(pk=product_id)
内容的提问来源于stack exchange,提问作者pizhlo
相关产品推荐
相关产品推荐

