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

外卖网站Django开发:渲染表单前为Commande模型plat字段赋值

解决方案:在表单中传递菜品实例并完成份数验证

你的核心问题在于表单的clean方法无法访问到对应的Plat实例——因为你没有把plat字段加入表单的fields列表,所以cleaned_data.get('plat')必然返回None,导致后续访问plat.nb_portions触发AttributeError。

你已经尝试在视图中把plat传递给表单,这方向是对的,接下来需要完善表单的实现:

1. 修改CommandeForm的初始化方法

在表单的__init__中接收plat参数,并将其保存为表单实例的属性,这样clean方法就能直接访问到:

# forms.py
class CommandeForm(forms.ModelForm):
    class Meta:
        model = Commande
        fields = ['nb_portions', 'adresse_livraison']
        widgets = {
            'nb_portions': forms.NumberInput(attrs={'class': 'form-control'}),
            'adresse_livraison': forms.TextInput(attrs={'class': 'form-control'})
        }
        labels = {
            'adresse_livraison': 'Adresse de livraison (livraison à partir de 5 portions) :'
        }

    def __init__(self, *args, **kwargs):
        # 从kwargs中取出plat参数,再调用父类初始化方法
        self.plat = kwargs.pop('plat')
        super().__init__(*args, **kwargs)

    def clean(self):
        cleaned_data = super().clean()
        nb_portions = cleaned_data.get('nb_portions')

        # 先判断份数是否有效,避免None与整数比较的错误
        if nb_portions is not None:
            if nb_portions > self.plat.nb_portions:
                # 注意add_error的用法:第一个参数是字段名,第二个是错误消息
                self.add_error(
                    'nb_portions',
                    f"Le nombre de portions maximales disponibles pour ce plat est : {self.plat.nb_portions} portions."
                )
        return cleaned_data

2. 视图部分的验证

你已经修改了视图中表单的初始化方式,这部分是正确的:

# views.py
def commander(request, id):
    plat = get_object_or_404(Plat, id=id)
    if request.method == "POST":
        form = CommandeForm(request.POST, plat=plat)
        if form.is_valid():
            commande = form.save(commit=False)
            commande.user = request.user
            commande.plat = plat
            commande.date = plat.date_prep
            commande.save()
            return redirect(commande_validee)
    else:
        form = CommandeForm(plat=plat)
    return render(request, 'actualites/commander.html', locals())

关键修复点说明

  • 传递Plat实例到表单:通过__init__方法把plat传入并存储,避免依赖cleaned_data(因为表单不包含plat字段)。
  • 完善clean逻辑:先判断nb_portions是否存在,防止用户未填写时触发None > int的错误;同时修正add_error的用法,把错误绑定到nb_portions字段,让错误提示显示在对应输入框下方,提升用户体验。
  • 避免直接修改表单实例的模型字段:之前的commande.plat = plat是错误的,因为表单实例的plat不是模型字段,而是需要通过初始化参数传递。

这样修改后,表单就能正确验证所选份数是否超过菜品的可用份数,同时不会再触发AttributeError。

内容的提问来源于stack exchange,提问作者Julien Mertz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:02:32