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

在Django的UpdateView中使用update_session_auth_hash触发唯一约束错误

解决Django中UpdateView更新用户时触发Profile唯一约束错误

问题根源

你的ProfileUpdateForm的save方法每次执行都会调用Profile.objects.create()创建新的Profile记录,但当前用户已经存在对应的一对一关联Profile,重复创建会触发phoneNumber的唯一约束,导致IntegrityError。同时视图的form_valid方法重复调用form.save(),进一步加剧了这个问题。

解决方案

1. 修改表单的save方法:更新而非重复创建Profile

将创建逻辑改为获取已有Profile并更新,不存在时再创建,同时补充表单初始化填充和手机号唯一性验证:

class ProfileUpdateForm(UserCreationForm):
    phoneNumber = forms.CharField(required=False)
    address = forms.CharField(required=False)
    username = forms.CharField()
    email = forms.EmailField()
    password1 = forms.CharField(widget=forms.PasswordInput)
    password2 = forms.CharField(widget=forms.PasswordInput)

    class Meta(UserCreationForm.Meta):
        fields = UserCreationForm.Meta.fields + ('email',)
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].disabled = True
        # 初始化表单时填充已有Profile数据
        if self.instance.pk:
            try:
                profile = self.instance.profile
                self.fields['phoneNumber'].initial = profile.phoneNumber
                self.fields['address'].initial = profile.address
                self.fields['email'].initial = self.instance.email
            except Profile.DoesNotExist:
                pass

    def clean_phoneNumber(self):
        # 验证手机号唯一性,排除当前用户的手机号
        phone_number = self.cleaned_data.get('phoneNumber')
        if phone_number:
            duplicate = Profile.objects.exclude(user=self.instance).filter(phoneNumber=phone_number).exists()
            if duplicate:
                raise forms.ValidationError("该手机号已被其他用户使用")
        return phone_number

    def save(self, commit=True):
        user = super().save(commit=commit)
        # 获取或创建用户对应的Profile
        profile, created = Profile.objects.get_or_create(user=user)
        # 更新Profile字段
        profile.phoneNumber = self.cleaned_data['phoneNumber']
        profile.address = self.cleaned_data['address']
        profile.username = user.username
        profile.email = user.email
        if commit:
            profile.save()
        return user

2. 修正视图的form_valid方法,避免重复保存

原视图中两次执行保存逻辑会导致重复创建/更新,修改为:

class UserUpdate(LoginRequiredMixin, UpdateView):
    model = User
    form_class = ProfileUpdateForm
    template_name = 'single_pages/profile_update.html'
    success_url = reverse_lazy('single_pages:landing')
    login_url = '/login/'

    def form_valid(self, form):
        # 调用父类方法完成保存,表单已处理好Profile
        response = super().form_valid(form)
        # 更新会话认证哈希,保持用户登录状态
        update_session_auth_hash(self.request, self.object)
        return response

3. 修正Profile模型的正则表达式(可选)

原正则存在多余竖线,修正为合法格式:

phoneNumberRegex = RegexValidator(regex=r'^01([016789])-?([0-9]{3,4})-?([0-9]{4})$')

额外说明

  • Profile模型中的username和email字段与User模型冗余,建议直接从User模型获取,避免数据不一致。
  • 即便将Profile改为ForeignKey,核心逻辑仍需保持:更新已有关联记录而非重复创建,同时确保phoneNumber的唯一性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:10:20