Django提交表单时如何同时获取pk与表单输入,解决quantity为None报错
问题原因及修复方案
核心报错原因
你获取不到quantity参数的直接原因是模板的<input>标签缺少name属性:浏览器提交表单时,只会将带有name属性的表单字段纳入请求参数,你只给输入框加了id="quantity"(这个是给前端DOM操作使用的),没有配置name="quantity",所以request.GET里根本没有quantity这个键,.get()方法自然返回None。
其他隐含bug
除了上面的核心问题,你的代码还有几处会触发报错的逻辑问题:
request.GET.get('quantity')拿到的是字符串类型,没有转成整数就直接和数字类型的库存比较,会触发类型错误- 扣库存时的变量名写错:你定义的变量是
quantity_sold,但扣减时写的是item.quantity -= quantity,会报变量未定义错误 - 没有处理非GET请求的场景:如果请求不是GET方法,
quantity_sold变量根本不会被定义,直接使用会报错 - 用GET请求执行库存修改操作不符合HTTP规范,GET请求应该只用于数据查询,修改类操作建议用POST,避免被爬虫、预加载等场景误触发修改数据
- GET请求不需要携带
{% csrf_token %},只有POST请求需要校验CSRF
修复后的代码
1. 模板代码(建议改成POST提交)
<td> <form action="{% url 'stock:sell' pk=item.pk%}" method="POST"> {% csrf_token %} <input type="number" name="quantity" id="quantity" value="1" size="5" min="1"> <button type="submit" name="submit">Sell</button> </form> </td>
这里加了name="quantity",同时给输入框加了min="1"限制最低输入为1,避免用户输入负数或0。
2. 视图代码
def sell(request, pk): # 只允许POST请求访问这个接口 if request.method != 'POST': messages.warning(request, "非法请求") return HttpResponseRedirect(reverse('stock:show_stock')) # 获取并转换销售数量,做异常处理 try: quantity_sold = int(request.POST.get('quantity', 0)) except ValueError: messages.danger(request, "销售数量必须为有效数字") return HttpResponseRedirect(reverse('stock:show_stock')) # 校验数量合法性 if quantity_sold <= 0: messages.danger(request, "销售数量必须大于0") return HttpResponseRedirect(reverse('stock:show_stock')) # 获取商品 item = Item.objects.get(id=pk) if quantity_sold > int(item.quantity): messages.danger(request, "库存不足,无法完成销售") else: item.quantity -= quantity_sold item.save() messages.success(request, f"成功出售{quantity_sold}件{item.name}") return HttpResponseRedirect(reverse('stock:show_stock'))
更简便的实现方式
如果你的项目是小型内部使用的系统,还可以用Django自带的表单类简化参数校验逻辑,不需要手动写类型转换、范围判断的代码:
- 定义一个销售表单类:
from django import forms class SellForm(forms.Form): quantity = forms.IntegerField(min_value=1, required=True, error_messages={ 'min_value': '销售数量不能小于1', 'required': '请输入销售数量' })
- 视图里直接用表单校验:
def sell(request, pk): if request.method != 'POST': messages.warning(request, "非法请求") return HttpResponseRedirect(reverse('stock:show_stock')) form = SellForm(request.POST) if not form.is_valid(): for err in form.errors.values(): messages.danger(request, err[0]) return HttpResponseRedirect(reverse('stock:show_stock')) quantity_sold = form.cleaned_data['quantity'] item = Item.objects.get(id=pk) if quantity_sold > int(item.quantity): messages.danger(request, "库存不足,无法完成销售") else: item.quantity -= quantity_sold item.save() messages.success(request, f"成功出售{quantity_sold}件{item.name}") return HttpResponseRedirect(reverse('stock:show_stock'))
这种方式所有参数校验逻辑都由Django表单自动完成,代码更简洁,可维护性更高。
内容的提问来源于stack exchange,提问作者Nduati
相关产品推荐
相关产品推荐

