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

Django表单未验证模型唯一约束直接返回数据库约束校验错误问题

核心问题定位

你的自定义校验逻辑完全未执行,根因是2处低级错误:

  1. __init__、clean方法缩进错误,被写在了Meta内部类的范围内,不属于表单类,因此不会被Django调用
  2. 自定义的表单__init__要求传入username作为第一个参数,但视图层实例化表单时未传递该参数,即使方法缩进正确也无法正常执行

修复步骤

第一步:修正form.py的缩进和逻辑错误

from django import forms
from . models import Semana

class FormularioSemana(forms.ModelForm):

    class Meta:
        model = Semana
        fields = '__all__'
        widgets = {
            'lunes_inicio': forms.TimeInput(attrs={'type': 'time'}),
            'lunes_fin': forms.TimeInput(attrs={'type': 'time'}),
            'martes_inicio': forms.TimeInput(attrs={'type': 'time'}),
            'martes_fin': forms.TimeInput(attrs={'type': 'time'}),
            'miercoles_inicio': forms.TimeInput(attrs={'type': 'time'}),
            'miercoles_fin': forms.TimeInput(attrs={'type': 'time'}),
            'jueves_inicio': forms.TimeInput(attrs={'type': 'time'}),
            'jueves_fin': forms.TimeInput(attrs={'type': 'time'}),
            'viernes_inicio': forms.TimeInput(attrs={'type': 'time'}),
            'viernes_fin': forms.TimeInput(attrs={'type': 'time'}),
            'sabado_inicio': forms.TimeInput(attrs={'type': 'time'}),
            'sabado_fin': forms.TimeInput(attrs={'type': 'time'}),
            'domingo_inicio': forms.TimeInput(attrs={'type': 'time'}),
            'domingo_fin': forms.TimeInput(attrs={'type': 'time'}),
        }
    
    # 注意:__init__要和Meta同级,不要缩进在Meta里面
    def __init__(self, username, *args, **kwargs):
        super(FormularioSemana, self).__init__(*args, **kwargs)
        self.instance.username = username
        if not username.is_staff:
            # 修复变量错误:这里没有request变量,直接用传入的username
            self.fields['nombre'].queryset = Semana.stem.filter(username = username)

    # clean方法同样要和Meta同级
    def clean(self, *args, **kwargs):
        cleaned_data = super().clean(*args, **kwargs)
        nombre = cleaned_data['nombre']
        username = self.instance.username

        duplicates = Semana.stem.filter(
            nombre=nombre,
            username=username
        )
        if self.instance.pk:
            duplicates = duplicates.exclude(pk=self.instance.pk)
        if duplicates.exists():
            raise forms.ValidationError('El nombre de la semana existe!')
        # 必须返回cleaned_data
        return cleaned_data

第二步:修正views.py的表单实例化逻辑

def index(request):
    if request.method == 'POST':
        # 第一个参数传入request.user,匹配表单自定义__init__的要求
        form = FormularioSemana(request.user, request.POST)
        if form.is_valid():
            # 表单已经给instance赋值了username,不需要再手动赋值
            form.save()
            all_items = Semana.stem.filter(username = request.user)
            semana = FormularioSemana(request.user)
            messages.success(request, ('New item added...'))
        else:
            # 校验失败的情况要返回带错误的表单,不能直接new一个新表单
            semana = form
            all_items = Semana.stem.filter(username = request.user)
        return render (request, 'semana.html', {'form':semana, 'all_items':all_items})

    else:
        # GET请求实例化也要传username
        semana = FormularioSemana(request.user)
        all_items = Semana.stem.filter(username = request.user)
        return render(request, 'semana.html', {'form':semana, 'all_items':all_items})

额外注意点

你原来的视图校验失败后直接new了一个空表单返回,会导致前端看不到表单的错误提示,上面的修复代码也同步处理了这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 07:39:00