为什么 clean_password2() 方法有效但 Django usercreationform 中的 clean_password1() 无效
why does clean_password2() method work but not clean_password1() in Django usercreationform
如果有人可以向我解释,我正在尝试弄清楚为什么这会起作用。
我刚刚创建了一个自定义用户模型(如下所示),它使用 clean_password2(self):
(如下所示)方法进行密码验证,但是当我尝试使用 clean_password1(self):
(如下所示)时) 验证不起作用。为什么?当然使用 password1
或 password2
来清理数据是可行的,因为它们是相同的?
Django 文档声明我们可以对 clean/validate 数据使用 clean_<fieldname>():
方法,因为 password1
在我看来是一个应该有效的字段名。
自定义用户模型
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError("Users must have an email address")
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None):
user = self.create_user(email=email, password=password)
user.is_staff = True
user.is_admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField(verbose_name="Email Address", max_length=255, unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
这个有效
class UserCreationForm(forms.ModelForm):
password1 = forms.CharField(
label="Password",
help_text=password_validation.password_validators_help_text_html(),
widget=forms.PasswordInput,
)
password2 = forms.CharField(
label="Confirm Password",
help_text="Enter the same password as before for validation",
widget=forms.PasswordInput,
)
class Meta:
model = User
fields = ["email"]
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
这不是
def clean_password1(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return password1
总结:不要在clean_<fieldname>
方法中引用其他字段。改为在 clean
方法中执行此逻辑。 https://docs.djangoproject.com/en/stable/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
深入 Django 表单的原因。调用clean_<fieldname>
的方法如下:
def _clean_fields(self):
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
在 _clean_fields
中,每个字段都按照它们在表单中出现的顺序解析,这是第一次为该字段填写 cleaned_data
。因为字段列表中password1
在password2
之前,当clean_password1
是运行时,cleaned_data["password2"]
还没有设置。这是您的代码发生的情况(我添加了注释):
def clean_password1(self):
password1 = self.cleaned_data.get("password1")
# `"password2"` is not present in cleaned_data, so `password2` is set to None
password2 = self.cleaned_data.get("password2")
# With `password2 == None`, this condition resolves to false
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
# `password1` is returned without any validation error
return password1
clean_password2
起作用的原因是因为 password2
出现在字段列表的后面。
如果有人可以向我解释,我正在尝试弄清楚为什么这会起作用。
我刚刚创建了一个自定义用户模型(如下所示),它使用 clean_password2(self):
(如下所示)方法进行密码验证,但是当我尝试使用 clean_password1(self):
(如下所示)时) 验证不起作用。为什么?当然使用 password1
或 password2
来清理数据是可行的,因为它们是相同的?
Django 文档声明我们可以对 clean/validate 数据使用 clean_<fieldname>():
方法,因为 password1
在我看来是一个应该有效的字段名。
自定义用户模型
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError("Users must have an email address")
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None):
user = self.create_user(email=email, password=password)
user.is_staff = True
user.is_admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField(verbose_name="Email Address", max_length=255, unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
这个有效
class UserCreationForm(forms.ModelForm):
password1 = forms.CharField(
label="Password",
help_text=password_validation.password_validators_help_text_html(),
widget=forms.PasswordInput,
)
password2 = forms.CharField(
label="Confirm Password",
help_text="Enter the same password as before for validation",
widget=forms.PasswordInput,
)
class Meta:
model = User
fields = ["email"]
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
这不是
def clean_password1(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return password1
总结:不要在clean_<fieldname>
方法中引用其他字段。改为在 clean
方法中执行此逻辑。 https://docs.djangoproject.com/en/stable/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
深入 Django 表单的原因。调用clean_<fieldname>
的方法如下:
def _clean_fields(self):
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
在 _clean_fields
中,每个字段都按照它们在表单中出现的顺序解析,这是第一次为该字段填写 cleaned_data
。因为字段列表中password1
在password2
之前,当clean_password1
是运行时,cleaned_data["password2"]
还没有设置。这是您的代码发生的情况(我添加了注释):
def clean_password1(self):
password1 = self.cleaned_data.get("password1")
# `"password2"` is not present in cleaned_data, so `password2` is set to None
password2 = self.cleaned_data.get("password2")
# With `password2 == None`, this condition resolves to false
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
# `password1` is returned without any validation error
return password1
clean_password2
起作用的原因是因为 password2
出现在字段列表的后面。