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

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自带的表单类简化参数校验逻辑,不需要手动写类型转换、范围判断的代码:

  1. 定义一个销售表单类:
from django import forms

class SellForm(forms.Form):
    quantity = forms.IntegerField(min_value=1, required=True, error_messages={
        'min_value': '销售数量不能小于1',
        'required': '请输入销售数量'
    })
  1. 视图里直接用表单校验:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 06:57:04