Django 5.1 UserCreationForm не позволяет вводить пустые пароли
Я обновляю приложение Django 3.0 до версии 5.1 и медленно перехожу от одного минорного релиза к другому. Пока все хорошо.
Однако после обновления с Django 5.0 до 5.1 я увидел изменение поведения на странице «Создать нового пользователя», которая раньше разрешала пустые пароли, при этом генерировался случайный пароль, если он не был введен.
Теперь я больше не могу отправить пустой пароль. Я получаю ошибку «обязательное поле» для обоих полей пароля, хотя оба поля явно установлены как required=False
.
Я знаю, что в Django 5.1 произошли некоторые изменения (5.1.0, 5.1.1) в классе UserCreationForm
. Я попробовал использовать AdminUserCreationForm
вместо UserCreationForm
и установить для поля usable_password значение None
, но оно все равно не позволяет вводить пустые пароли, как раньше.
Есть идеи?
Окружение
Python 3.12.8
Django 5.1.5
Упрощенный код
class SignupForm(AdminUserCreationForm): # previously using UserCreationForm
usable_password = None # Newly added
# Form fields
sharedaccountflag = forms.ChoiceField(
label='Cuenta compartida',
required=True,
choices=BOOLEAN_CHOICES
)
# Constructor
def __init__(self, *args, **kwargs):
# Call base class constructor (i.e. SignupForm)
super(SignupForm, self).__init__(*args, **kwargs)
# Set password fields as optional
self.fields['password1'].required=False
self.fields['password2'].required=False
# Set form helper properties
self.helper = FormHelper()
setFormHelper(self.helper) # set form method (POST / GET) and styling
self.helper.form_tag = False
# Set form layout
self.helper.layout = Layout(
Fieldset(
'password1',
'password2',
'sharedaccountflag'
)
)
# Specify model and which fields to include in form
class Meta:
model = get_user_model()
fields = ('password1', 'password2', 'sharedaccountflag')
Да. В новых версиях Django
исходный код изменился, соответственно изменилось и поведение класса BaseUserCreationForm
. Теперь поля password1
и password2
создаются с помощью статического метода SetPasswordMixin.create_password_fields()
, и по умолчанию они принимают значение required=False
. Это можно легко проверить здесь. Но даже если поля необязательны, метод validate_passwords
всегда вызывается , в методе clean
и проверяет, что поля не пусты. Например, когда вы вызываете что-то вроде этого form.is_valid()
, будет вызван clean
.
Если вам нужно поведение, в котором разрешены пустые пароли, то, учитывая required=False
, вы можете определить пользовательский validate_passwords
метод, подобный приведенному ниже, который позволит вам создавать пользователей с пустыми паролями:
from django.contrib.auth import forms
class CustomUserCreationForm(forms.UserCreationForm):
def validate_passwords(
self,
password1_field_name: str = "password1",
password2_field_name: str = "password2"):
def is_password_field_required_and_not_valid(field_name: str) -> bool:
is_required = self.fields[field_name].required
cleaned_value = self.cleaned_data.get(field_name)
is_field_has_errors = field_name in self.errors
return (
is_required
and not cleaned_value
and not is_field_has_errors
)
if is_password_field_required_and_not_valid(password1_field_name):
error = ValidationError(
self.fields[password1_field_name].error_messages["required"],
code="required",
)
self.add_error(password1_field_name, error)
if is_password_field_required_and_not_valid(password2_field_name):
error = ValidationError(
self.fields[password2_field_name].error_messages["required"],
code="required",
)
self.add_error(password2_field_name, error)
password1 = self.cleaned_data.get(password1_field_name)
password2 = self.cleaned_data.get(password2_field_name)
if password1 != password2:
error = ValidationError(
self.error_messages["password_mismatch"],
code="password_mismatch",
)
self.add_error(password2_field_name, error)
p.s. Я не уверен, так ли это было задумано, возможно, просто допущена ошибка, в validate_passwords
, где флаг required
просто не учитывается.