diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index f279f5e893..18ea52c414 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -94,7 +94,8 @@ class UserCreationForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(UserCreationForm, self).__init__(*args, **kwargs) - self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus': ''}) + if self._meta.model.USERNAME_FIELD in self.fields: + self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus': ''}) def clean_password2(self): password1 = self.cleaned_data.get("password1") diff --git a/docs/releases/1.10.1.txt b/docs/releases/1.10.1.txt index b5c72c5e8b..2fd860527a 100644 --- a/docs/releases/1.10.1.txt +++ b/docs/releases/1.10.1.txt @@ -76,3 +76,6 @@ Bugfixes * Included the already applied migration state changes in the ``Apps`` instance provided to the ``pre_migrate`` signal receivers to allow ``ContentType`` renaming to be performed on model rename (:ticket:`27100`). + +* Reallowed subclassing ``UserCreationForm`` without ``USERNAME_FIELD`` in + ``Meta.fields`` (:ticket:`27111`). diff --git a/tests/auth_tests/test_forms.py b/tests/auth_tests/test_forms.py index fe22d1e20b..64c095bf2a 100644 --- a/tests/auth_tests/test_forms.py +++ b/tests/auth_tests/test_forms.py @@ -22,7 +22,9 @@ from django.utils.encoding import force_text from django.utils.text import capfirst from django.utils.translation import ugettext as _ -from .models.custom_user import CustomUser, ExtensionUser +from .models.custom_user import ( + CustomUser, CustomUserWithoutIsActiveField, ExtensionUser, +) from .settings import AUTH_TEMPLATES @@ -208,6 +210,20 @@ class UserCreationFormTest(TestDataMixin, TestCase): form = CustomUserCreationForm(data) self.assertTrue(form.is_valid()) + def test_custom_form_hidden_username_field(self): + class CustomUserCreationForm(UserCreationForm): + class Meta(UserCreationForm.Meta): + model = CustomUserWithoutIsActiveField + fields = ('email',) # without USERNAME_FIELD + + data = { + 'email': 'testclient@example.com', + 'password1': 'testclient', + 'password2': 'testclient', + } + form = CustomUserCreationForm(data) + self.assertTrue(form.is_valid()) + def test_password_whitespace_not_stripped(self): data = { 'username': 'testuser',