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

Django 3.2.9重写表单save方法触发The given username must be set错误如何解决

Django 3.2.9 重写表单save方法报ValueError问题排查

问题现象

使用Django 3.2.9开发项目时,重写表单save方法出现如下报错:

ValueError The given username must be set from form self

不重写save方法时,视图中直接调用保存功能运行正常;重写后表单无法读取self属性,但表单类内其他校验方法可以正常读取self属性。

相关代码

自定义注册表单类代码

class RegisterForm(forms.Form):
    username=forms.CharField(
        required=True,
        min_length=4,max_length=50,
        widget=TextInput(attrs={
            'class':'form-control'
        })
    )
    email=forms.EmailField(
        required=True,
        min_length=4,max_length=50,
        widget=TextInput(attrs={
            'class':'form-control'
        })
    )
    pwd=forms.CharField(
        required=True,
        min_length=4,max_length=50,
        widget=PasswordInput(attrs={
            'class':'form-control'
        })
    )
    pwdr=forms.CharField(
        required=True,
        min_length=4,max_length=50,
        widget=PasswordInput(attrs={
            'class':'form-control'
        })
    )

    def clean_username(self):
        username=self.cleaned_data.get('username')
        if User.objects.filter(username=username).exists():
            raise forms.ValidationError('该用户名已被使用')
        return username

    def clean_email(self):
        email=self.cleaned_data.get('email')
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError('该邮箱已被使用')
        return email

    def clean(self):
        cleaned_data=super().clean()

        if cleaned_data.get('pwd')!= cleaned_data.get('pwdr'):
            self.add_error('pwdr','两次输入的密码不一致')
            return redirect('register')

        return redirect('home')

    def save(self):
        username=self.cleaned_data.get('username')
        email=self.cleaned_data.get('email')
        pwd=self.cleaned_data.get('pwd')
        
        return User.objects.create_user(
            username,
            email,
            pwd
        )

问题排查

save方法内打印self的结果为表单渲染后的HTML片段:

label for="id_username">Username:
Email: Pwd: Pwdr:

查阅Django官方文档发现相关说明:

注意:调用Form.add_error()方法时会自动将相关字段从cleaned_data中移除。

问题根源

clean方法写法不符合Django表单校验规范:

  • 全局clean方法仅需处理校验逻辑,校验通过时返回cleaned_data即可,不需要返回redirect响应
  • 校验不通过时抛出ValidationError即可,不需要调用add_error后返回redirect响应
    错误的返回逻辑导致cleaned_data未被正确传递,后续save方法读取cleaned_data中的字段时得到None,最终触发ValueError。

修复方案

修改clean方法为如下写法即可:

def clean(self):
    cleaned_data = super().clean()
    pwd = cleaned_data.get('pwd')
    pwdr = cleaned_data.get('pwdr')
    if pwd != pwdr:
        raise forms.ValidationError('两次输入的密码不一致')
    return cleaned_data

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 09:06:02