diff options
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/auth/admin.py | 4 | ||||
| -rw-r--r-- | django/contrib/auth/forms.py | 98 |
2 files changed, 66 insertions, 36 deletions
diff --git a/django/contrib/auth/admin.py b/django/contrib/auth/admin.py index 8e1d63ef07..e977d3ded5 100644 --- a/django/contrib/auth/admin.py +++ b/django/contrib/auth/admin.py @@ -5,8 +5,8 @@ from django.contrib.admin.utils import unquote from django.contrib.auth import update_session_auth_hash from django.contrib.auth.forms import ( AdminPasswordChangeForm, + AdminUserCreationForm, UserChangeForm, - UserCreationForm, ) from django.contrib.auth.models import Group, User from django.core.exceptions import PermissionDenied @@ -71,7 +71,7 @@ class UserAdmin(admin.ModelAdmin): ), ) form = UserChangeForm - add_form = UserCreationForm + add_form = AdminUserCreationForm change_password_form = AdminPasswordChangeForm list_display = ("username", "email", "first_name", "last_name", "is_staff") list_filter = ("is_staff", "is_superuser", "is_active", "groups") diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index 31e96ff91c..a11668944a 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -96,18 +96,11 @@ class UsernameField(forms.CharField): class SetPasswordMixin: """ Form mixin that validates and sets a password for a user. - - This mixin also support setting an unusable password for a user. """ error_messages = { "password_mismatch": _("The two password fields didn’t match."), } - usable_password_help_text = _( - "Whether the user will be able to authenticate using a password or not. " - "If disabled, they may still be able to authenticate using other backends, " - "such as Single Sign-On or LDAP." - ) @staticmethod def create_password_fields(label1=_("Password"), label2=_("Password confirmation")): @@ -127,33 +120,14 @@ class SetPasswordMixin: ) return password1, password2 - @staticmethod - def create_usable_password_field(help_text=usable_password_help_text): - return forms.ChoiceField( - label=_("Password-based authentication"), - required=False, - initial="true", - choices={"true": _("Enabled"), "false": _("Disabled")}, - widget=forms.RadioSelect(attrs={"class": "radiolist inline"}), - help_text=help_text, - ) - def validate_passwords( self, password1_field_name="password1", password2_field_name="password2", - usable_password_field_name="usable_password", ): - usable_password = ( - self.cleaned_data.pop(usable_password_field_name, None) != "false" - ) - self.cleaned_data["set_usable_password"] = usable_password password1 = self.cleaned_data.get(password1_field_name) password2 = self.cleaned_data.get(password2_field_name) - if not usable_password: - return self.cleaned_data - if not password1 and password1_field_name not in self.errors: error = ValidationError( self.fields[password1_field_name].error_messages["required"], @@ -177,19 +151,68 @@ class SetPasswordMixin: def validate_password_for_user(self, user, password_field_name="password2"): password = self.cleaned_data.get(password_field_name) - if password and self.cleaned_data["set_usable_password"]: + if password: try: password_validation.validate_password(password, user) except ValidationError as error: self.add_error(password_field_name, error) def set_password_and_save(self, user, password_field_name="password1", commit=True): + user.set_password(self.cleaned_data[password_field_name]) + if commit: + user.save() + return user + + +class SetUnusablePasswordMixin: + """ + Form mixin that allows setting an unusable password for a user. + + This mixin should be used in combination with `SetPasswordMixin`. + """ + + usable_password_help_text = _( + "Whether the user will be able to authenticate using a password or not. " + "If disabled, they may still be able to authenticate using other backends, " + "such as Single Sign-On or LDAP." + ) + + @staticmethod + def create_usable_password_field(help_text=usable_password_help_text): + return forms.ChoiceField( + label=_("Password-based authentication"), + required=False, + initial="true", + choices={"true": _("Enabled"), "false": _("Disabled")}, + widget=forms.RadioSelect(attrs={"class": "radiolist inline"}), + help_text=help_text, + ) + + def validate_passwords( + self, + *args, + usable_password_field_name="usable_password", + **kwargs, + ): + usable_password = ( + self.cleaned_data.pop(usable_password_field_name, None) != "false" + ) + self.cleaned_data["set_usable_password"] = usable_password + + if usable_password: + super().validate_passwords(*args, **kwargs) + + def validate_password_for_user(self, user, **kwargs): if self.cleaned_data["set_usable_password"]: - user.set_password(self.cleaned_data[password_field_name]) + super().validate_password_for_user(user, **kwargs) + + def set_password_and_save(self, user, commit=True, **kwargs): + if self.cleaned_data["set_usable_password"]: + user = super().set_password_and_save(user, **kwargs, commit=commit) else: user.set_unusable_password() - if commit: - user.save() + if commit: + user.save() return user @@ -197,10 +220,12 @@ class BaseUserCreationForm(SetPasswordMixin, forms.ModelForm): """ A form that creates a user, with no privileges, from the given username and password. + + This is the documented base class for customizing the user creation form. + It should be kept mostly unchanged to ensure consistency and compatibility. """ password1, password2 = SetPasswordMixin.create_password_fields() - usable_password = SetPasswordMixin.create_usable_password_field() class Meta: model = User @@ -520,13 +545,13 @@ class PasswordChangeForm(SetPasswordForm): return old_password -class AdminPasswordChangeForm(SetPasswordMixin, forms.Form): +class AdminPasswordChangeForm(SetUnusablePasswordMixin, SetPasswordMixin, forms.Form): """ A form used to change the password of a user in the admin interface. """ required_css_class = "required" - usable_password_help_text = SetPasswordMixin.usable_password_help_text + ( + usable_password_help_text = SetUnusablePasswordMixin.usable_password_help_text + ( '<ul id="id_unusable_warning" class="messagelist"><li class="warning">' "If disabled, the current password for this user will be lost.</li></ul>" ) @@ -538,7 +563,7 @@ class AdminPasswordChangeForm(SetPasswordMixin, forms.Form): self.fields["password1"].widget.attrs["autofocus"] = True if self.user.has_usable_password(): self.fields["usable_password"] = ( - SetPasswordMixin.create_usable_password_field( + SetUnusablePasswordMixin.create_usable_password_field( self.usable_password_help_text ) ) @@ -558,3 +583,8 @@ class AdminPasswordChangeForm(SetPasswordMixin, forms.Form): if "set_usable_password" in data or "password1" in data and "password2" in data: return ["password"] return [] + + +class AdminUserCreationForm(SetUnusablePasswordMixin, UserCreationForm): + + usable_password = SetUnusablePasswordMixin.create_usable_password_field() |
