From d8dfff2ab0edf7a1ca5255eccf45c447b2f9d57e Mon Sep 17 00:00:00 2001 From: Timo Ludwig Date: Wed, 2 Dec 2020 11:23:52 +0100 Subject: [PATCH] Fixed #32235 -- Made ReadOnlyPasswordHashField disabled by default. --- django/contrib/auth/forms.py | 15 +-------------- docs/releases/3.2.txt | 5 +++++ docs/topics/auth/customizing.txt | 15 ++++++++------- tests/auth_tests/test_forms.py | 1 + 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index b9eb33329f3..20d89227990 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -56,16 +56,9 @@ class ReadOnlyPasswordHashField(forms.Field): def __init__(self, *args, **kwargs): kwargs.setdefault("required", False) + kwargs.setdefault('disabled', True) super().__init__(*args, **kwargs) - def bound_data(self, data, initial): - # Always return initial because the widget doesn't - # render an input field. - return initial - - def has_changed(self, initial, data): - return False - class UsernameField(forms.CharField): def to_python(self, value): @@ -163,12 +156,6 @@ class UserChangeForm(forms.ModelForm): if user_permissions: user_permissions.queryset = user_permissions.queryset.select_related('content_type') - def clean_password(self): - # Regardless of what the user provides, return the initial value. - # This is done here, rather than on the field, because the - # field does not have access to the initial value - return self.initial.get('password') - class AuthenticationForm(forms.Form): """ diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt index 7d374da0a7e..2ab8546026f 100644 --- a/docs/releases/3.2.txt +++ b/docs/releases/3.2.txt @@ -625,6 +625,11 @@ Miscellaneous using :option:`makemessages --locale` option, when they contain hyphens (``'-'``). +* The ``django.contrib.auth.forms.ReadOnlyPasswordHashField`` form field is now + :attr:`~django.forms.Field.disabled` by default. Therefore + ``UserChangeForm.clean_password()`` is no longer required to return the + initial value. + .. _deprecated-features-3.2: Features deprecated in 3.2 diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt index 6ab83054688..8314d9f1711 100644 --- a/docs/topics/auth/customizing.txt +++ b/docs/topics/auth/customizing.txt @@ -1129,7 +1129,7 @@ code would be required in the app's ``admin.py`` file:: class UserChangeForm(forms.ModelForm): """A form for updating users. Includes all the fields on the user, but replaces the password field with admin's - password hash display field. + disabled password hash display field. """ password = ReadOnlyPasswordHashField() @@ -1137,12 +1137,6 @@ code would be required in the app's ``admin.py`` file:: model = MyUser fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin') - def clean_password(self): - # Regardless of what the user provides, return the initial value. - # This is done here, rather than on the field, because the - # field does not have access to the initial value - return self.initial["password"] - class UserAdmin(BaseUserAdmin): # The forms to add and change user instances @@ -1182,3 +1176,10 @@ Finally, specify the custom model as the default user model for your project using the :setting:`AUTH_USER_MODEL` setting in your ``settings.py``:: AUTH_USER_MODEL = 'customauth.MyUser' + +.. versionchanged:: 3.2 + + In older versions, ``ReadOnlyPasswordHashField`` is not + :attr:`~django.forms.Field.disabled` by default and + ``UserChangeForm.clean_password()`` is required to return the initial + value, whatever the user provides. diff --git a/tests/auth_tests/test_forms.py b/tests/auth_tests/test_forms.py index 88b4b326671..7a731bedc87 100644 --- a/tests/auth_tests/test_forms.py +++ b/tests/auth_tests/test_forms.py @@ -1022,6 +1022,7 @@ class ReadOnlyPasswordHashTest(SimpleTestCase): def test_readonly_field_has_changed(self): field = ReadOnlyPasswordHashField() + self.assertIs(field.disabled, True) self.assertFalse(field.has_changed('aaa', 'bbb'))