首页 > 解决方案 > django modelform 覆盖 save() 方法 self.instance 已更改

问题描述

我正在制作用户信息页面。

在视图中,我通过这样的request.user形式

form = UserForm(request.POST, instance=request.user)

问题是,当我用 保存表单时form.save(),用户名已更改,并且我已签self.isntance入,但UserForm我发现方法self.instance.username中的save()已更改,但字段的干净方法(clean_username())和表单子类的clean()方法中没有。 self.instance.username只是在save()方法上有所改变。

我有另一个带有 Usermodel 的字段,例如电子邮件字段,但只有用户名字段被更改。

任何建议或线索对我都有好处

附言。在我写完这个问题之后,我发现方法中的另一件事self.instance不是save()原始用户实例。它的用户名和电子邮件是 request.POST 数据。

这是我的代码

看法

@login_required(login_url='/member/login')
def change_user_info(request):
    if request.method == 'POST':
        form = UserForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            update_session_auth_hash(request, form.instance)
            return redirect('/member/change-user-info')
    else:
        form = UserForm(instance=request.user)
    context = {
        'form': form,
        'home_button': True
    }
    return render(request, 'member/user_info.html', context)

模型

class User(AbstractUser):
    username = models.CharField(max_length=50, unique=True)
    email = models.EmailField()


    USERNAME_FIELD = 'username'
    EMAIL_FIELD = 'email'

形式

class UserForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        field_list = ['username', 'email']
        for field in field_list:
            self.fields[field].required = False

    new_password1 = forms.CharField(
        required=False,
        widget=forms.PasswordInput(
            attrs={
                'autofocus': True,
                'id': 'userinfo-new-password1',
                'class': 'form-control',
                'placeholder': '새 비밀번호',
                'aria-describedby': 'newpassword1HelpBlock',
            }),
    )
    new_password2 = forms.CharField(
        required=False,
        widget=forms.PasswordInput(
            attrs={
                'autofocus': True,
                'id': 'userinfo-new-password2',
                'class': 'form-control',
                'placeholder': '새 비밀번호 확인',
                'aria-describedby': 'newpassword2HelpBlock',
            }),
    )
    old_password = forms.CharField(
        required=False,
        widget=forms.PasswordInput(
            attrs={
                'autofocus': True,
                'id': 'userinfo-old-password',
                'class': 'form-control',
                'placeholder': '기존 비밀번호',
                'aria-describedby': 'oldpasswordHelpBlock',
            })
    )

    class Meta:
        model = User
        fields = [
            'username',
            'email',
        ]
        widgets = {
            'username': TextInput(attrs={
                # 'readonly': True,
                'disabled': True,
                'autofocus': True,
                'id': 'disabledTextInput',
                'class': 'form-control',
                'aria-describedby': 'usernameHelpBlock',
            }),
            'email': EmailInput(attrs={
                'autofocus': True,
                'id': 'userinfo-email',
                'class': 'form-control',
                'placeholder': 'EMAIL',
                'aria-describedby': 'emailHelpBlock',
            }),
        }

    def clean_username(self):
        test = self.cleaned_data['username']  --> ''
        test2 = self.instance.username   --> has correct user name
        return test

    def clean_new_password1(self):
        if not self.cleaned_data.get('new_password1'):
            return None
        return self.cleaned_data['new_password1']

    def clean_new_password2(self):
        if not self.cleaned_data.get('new_password2'):
            return None
        return self.cleaned_data['new_password2']

    def clean_old_password(self):
        password = self.cleaned_data.get('old_password')
        if not self.instance.check_password(password):
            raise forms.ValidationError('정보 변경을 위해서 기존 비밀번호를 입력해 주세요')
        return password

    def clean(self):
        test = self.instance.username --> has correct username
        super().clean()
        new_password1 = self.cleaned_data.get('new_password1')
        new_password2 = self.cleaned_data.get('new_password2')

        if new_password1 and new_password2:
            if new_password1 != new_password2:
                raise forms.ValidationError(
                    "새 비밀번호가 일치하지 않습니다."
                )
        elif new_password1 is None and new_password2 is None:
            pass
        else:
            raise forms.ValidationError(
                "비밀번호 변경을 위해선 '새 비밀번호' '새 비밀번호 확인'란에 모두 입력하셔야 합니다."
            )

    def save(self, commit=True):
        user = self.instance
        username = self.instance.username --> ''
        email = self.instance.email --> has correct email
        if self.instance.email != self.cleaned_data.get('email'):
            user.email = self.cleaned_data.get('email')
        if self.cleaned_data['new_password2'] is not None:
            user.set_password(self.cleaned_data.get('new_password2'))
        user.save()

谢谢

标签: djangomodelform

解决方案


您可以从 访问原始值self.initial,也就是说,如果您向表单提供了初始值。


推荐阅读