11"""EmailUser forms."""
22from django import forms
3- from django .contrib .auth import get_user_model
3+ from django .contrib .auth import get_user_model , password_validation
44from django .contrib .auth .forms import ReadOnlyPasswordHashField
5+ from django .core .exceptions import ValidationError
56from django .utils .translation import gettext_lazy as _
67
78
89class EmailUserCreationForm (forms .ModelForm ):
9-
1010 """
1111 A form for creating new users.
1212
1313 Includes all the required fields, plus a repeated password.
14-
1514 """
1615
1716 error_messages = {
1817 "duplicate_email" : _ ("A user with that email already exists." ),
1918 "password_mismatch" : _ ("The two password fields didn't match." ),
2019 }
2120
22- password1 = forms .CharField (label = _ ("Password" ), widget = forms .PasswordInput )
21+ password1 = forms .CharField (
22+ label = _ ("Password" ),
23+ strip = False ,
24+ widget = forms .PasswordInput (attrs = {"autocomplete" : "new-password" }),
25+ help_text = password_validation .password_validators_help_text_html (),
26+ )
2327 password2 = forms .CharField (
2428 label = _ ("Password confirmation" ),
25- widget = forms .PasswordInput ,
26- help_text = _ ("Enter the same password as above, for verification." ),
29+ widget = forms .PasswordInput (attrs = {"autocomplete" : "new-password" }),
30+ strip = False ,
31+ help_text = _ ("Enter the same password as before, for verification." ),
2732 )
2833
29- class Meta : # noqa: D101
34+ class Meta :
3035 model = get_user_model ()
3136 fields = ("email" ,)
3237
@@ -35,8 +40,7 @@ def clean_email(self):
3540 Clean form email.
3641
3742 :return str email: cleaned email
38- :raise forms.ValidationError: Email is duplicated
39-
43+ :raise ValidationError: Email is duplicated
4044 """
4145 # Since EmailUser.email is unique, this check is redundant,
4246 # but it sets a nicer error message than the ORM. See #13147.
@@ -45,7 +49,7 @@ def clean_email(self):
4549 get_user_model ()._default_manager .get (email = email )
4650 except get_user_model ().DoesNotExist :
4751 return email
48- raise forms . ValidationError (
52+ raise ValidationError (
4953 self .error_messages ["duplicate_email" ],
5054 code = "duplicate_email" ,
5155 )
@@ -55,28 +59,37 @@ def clean_password2(self):
5559 Check that the two password entries match.
5660
5761 :return str password2: cleaned password2
58- :raise forms.ValidationError: password2 != password1
59-
62+ :raise ValidationError: password2 != password1
6063 """
6164 password1 = self .cleaned_data .get ("password1" )
6265 password2 = self .cleaned_data .get ("password2" )
6366 if password1 and password2 and password1 != password2 :
64- raise forms . ValidationError (
67+ raise ValidationError (
6568 self .error_messages ["password_mismatch" ],
6669 code = "password_mismatch" ,
6770 )
6871 return password2
6972
73+ def _post_clean (self ):
74+ super ()._post_clean ()
75+ # Validate the password after self.instance is updated with form data
76+ # by super().
77+ password = self .cleaned_data .get ("password2" )
78+ if password :
79+ try :
80+ password_validation .validate_password (password , self .instance )
81+ except ValidationError as error :
82+ self .add_error ("password2" , error )
83+
7084 def save (self , commit = True ):
7185 """
7286 Save user.
7387
7488 Save the provided password in hashed format.
7589
7690 :return custom_user.models.EmailUser: user
77-
7891 """
79- user = super (EmailUserCreationForm , self ).save (commit = False )
92+ user = super ().save (commit = False )
8093 user .set_password (self .cleaned_data ["password1" ])
8194 if commit :
8295 user .save ()
@@ -90,39 +103,28 @@ class EmailUserChangeForm(forms.ModelForm):
90103
91104 Includes all the fields on the user, but replaces the password field
92105 with admin's password hash display field.
93-
94106 """
95107
96108 password = ReadOnlyPasswordHashField (
97109 label = _ ("Password" ),
98110 help_text = _ (
99- "Raw passwords are not stored, so there is no way to see "
100- "this user's password, but you can change the password "
101- 'using <a href="%(url)s">this form</a>.'
102- )
103- % {"url" : "../password/" },
111+ "Raw passwords are not stored, so there is no way to see this "
112+ "user's password, but you can change the password using "
113+ '<a href="{}">this form</a>.'
114+ ),
104115 )
105116
106- class Meta : # noqa: D101
117+ class Meta :
107118 model = get_user_model ()
108119 exclude = ()
109120
110121 def __init__ (self , * args , ** kwargs ):
111- """Init the form."""
112- super (EmailUserChangeForm , self ).__init__ (* args , ** kwargs )
113- f = self .fields .get ("user_permissions" , None )
114- if f is not None :
115- f .queryset = f .queryset .select_related ("content_type" )
116-
117- def clean_password (self ):
118- """
119- Clean password.
120-
121- Regardless of what the user provides, return the initial value.
122- This is done here, rather than on the field, because the
123- field does not have access to the initial value.
124-
125- :return str password:
126-
127- """
128- return self .initial ["password" ]
122+ super ().__init__ (* args , ** kwargs )
123+ password = self .fields .get ("password" )
124+ if password :
125+ password .help_text = password .help_text .format ("../password/" )
126+ user_permissions = self .fields .get ("user_permissions" )
127+ if user_permissions :
128+ user_permissions .queryset = user_permissions .queryset .select_related (
129+ "content_type"
130+ )
0 commit comments