【问题标题】:django modelform overriding save() method self.instance changeddjango modelform 覆盖 save() 方法 self.instance 已更改
【发布时间】:2018-10-12 03:20:18
【问题描述】:

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

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

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

问题是当我使用form.save() 保存表单时,用户名已更改并且我检查了self.isntanceUserForm 中,然后我发现save() 方法中的self.instance.username 已更改,但在该字段的清理方法(clean_username())和表单子类的clean()方法。 self.instance.username 仅在 save() 方法中更改。

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

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

ps。在我写完这个问题后,我发现self.instance in save()method 不是原始用户实例。 它的用户名和电子邮件是 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()

谢谢

【问题讨论】:

    标签: django modelform


    【解决方案1】:

    您在表单中的用户名字段被禁用,原因是您在 clean_username 方法中的 self.cleaned_data['username'] 中获得空白值。所以改变你的代码如下

    def clean_username(self):
        return self.cleaned_data['username']  or self.instance.username
    

    【讨论】:

    • 是的,我明白了,它可以是解决方案之一~!!但是我无法理解的是为什么save()方法中的self.instancerequest.POSTdata改变了。即使我覆盖了save() 方法。我认为self.instance不应该在self.instance.save()之前更改save()method...
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2018-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      • 2013-07-20
      • 1970-01-01
      • 2010-10-23
      • 2011-07-08
      相关资源
      最近更新 更多