diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
index 9279c52..0c542be 100644
|
a
|
b
|
class UserCreationForm(forms.ModelForm):
|
| 82 | 82 | def clean_username(self): |
| 83 | 83 | # Since User.username is unique, this check is redundant, |
| 84 | 84 | # but it sets a nicer error message than the ORM. See #13147. |
| | 85 | UserModel = self._meta.model |
| 85 | 86 | username = self.cleaned_data["username"] |
| 86 | 87 | try: |
| 87 | | User.objects.get(username=username) |
| 88 | | except User.DoesNotExist: |
| | 88 | UserModel.objects.get(username=username) |
| | 89 | except UserModel.DoesNotExist: |
| 89 | 90 | return username |
| 90 | 91 | raise forms.ValidationError(self.error_messages['duplicate_username']) |
| 91 | 92 | |
diff --git a/django/contrib/auth/tests/forms.py b/django/contrib/auth/tests/forms.py
index f3eb242..b63624c 100644
|
a
|
b
|
from django.contrib.auth.models import User
|
| 5 | 5 | from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm, |
| 6 | 6 | PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm) |
| 7 | 7 | from django.contrib.auth.tests.utils import skipIfCustomUser |
| | 8 | from django.contrib.auth.tests.custom_user import ExtensionUser |
| 8 | 9 | from django.core import mail |
| 9 | 10 | from django.forms.fields import Field, EmailField |
| 10 | 11 | from django.test import TestCase |
| … |
… |
class PasswordResetFormTest(TestCase):
|
| 362 | 363 | self.assertFalse(form.is_valid()) |
| 363 | 364 | self.assertEqual(form["email"].errors, |
| 364 | 365 | [_("The user account associated with this email address cannot reset the password.")]) |
| | 366 | |
| | 367 | |
| | 368 | @override_settings(AUTH_USER_MODEL='auth.ExtensionUser') |
| | 369 | class CustomUserCreationFormTest(TestCase): |
| | 370 | def test_form_validates(self): |
| | 371 | class CustomUserCreationForm(UserCreationForm): |
| | 372 | class Meta(UserCreationForm.Meta): |
| | 373 | model = ExtensionUser |
| | 374 | data = { |
| | 375 | 'username': 'jsmith', |
| | 376 | 'password1': 'test123', |
| | 377 | 'password2': 'test123', |
| | 378 | } |
| | 379 | form = CustomUserCreationForm(data) |
| | 380 | self.assertTrue(form.is_valid()) |
diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt
index e313b23..297214c 100644
|
a
|
b
|
As you may expect, built-in Django's :ref:`forms <built-in-auth-forms>`
|
| 2061 | 2061 | and :ref:`views <other-built-in-views>` make certain assumptions about |
| 2062 | 2062 | the user model that they are working with. |
| 2063 | 2063 | |
| 2064 | | If your user model doesn't follow the same assumptions, it may be necessary to define |
| 2065 | | a replacement form, and pass that form in as part of the configuration of the |
| 2066 | | auth views. |
| | 2064 | The following forms are compatible with any subclass of |
| | 2065 | :class:`~django.contrib.auth.models.AbstractBaseUser`: |
| 2067 | 2066 | |
| 2068 | | * :class:`~django.contrib.auth.forms.UserCreationForm` |
| | 2067 | * :class:`~django.contrib.auth.forms.AuthenticationForm` |
| 2069 | 2068 | |
| 2070 | | Depends on the :class:`~django.contrib.auth.models.User` model. |
| 2071 | | Must be re-written for any custom user model. |
| | 2069 | Uses the field defined in `USERNAME_FIELD`. |
| 2072 | 2070 | |
| 2073 | | * :class:`~django.contrib.auth.forms.UserChangeForm` |
| | 2071 | * :class:`~django.contrib.auth.forms.SetPasswordForm` |
| 2074 | 2072 | |
| 2075 | | Depends on the :class:`~django.contrib.auth.models.User` model. |
| 2076 | | Must be re-written for any custom user model. |
| | 2073 | * :class:`~django.contrib.auth.forms.PasswordChangeForm` |
| 2077 | 2074 | |
| 2078 | | * :class:`~django.contrib.auth.forms.AuthenticationForm` |
| | 2075 | * :class:`~django.contrib.auth.forms.AdminPasswordChangeForm` |
| 2079 | 2076 | |
| 2080 | | Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser`, |
| 2081 | | and will adapt to use the field defined in `USERNAME_FIELD`. |
| | 2077 | The following forms make assumptions about the user model and can be used as-is if they are met: |
| 2082 | 2078 | |
| 2083 | 2079 | * :class:`~django.contrib.auth.forms.PasswordResetForm` |
| 2084 | 2080 | |
| … |
… |
auth views.
|
| 2086 | 2082 | `email` that can be used to identify the user, and a boolean field |
| 2087 | 2083 | named `is_active` to prevent password resets for inactive users. |
| 2088 | 2084 | |
| 2089 | | * :class:`~django.contrib.auth.forms.SetPasswordForm` |
| | 2085 | Finally, the following forms are tied directly to auth.User and need to be re-written or extended to work with a custom user model: |
| 2090 | 2086 | |
| 2091 | | Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` |
| | 2087 | * :class:`~django.contrib.auth.forms.UserCreationForm` |
| 2092 | 2088 | |
| 2093 | | * :class:`~django.contrib.auth.forms.PasswordChangeForm` |
| | 2089 | * :class:`~django.contrib.auth.forms.UserChangeForm` |
| 2094 | 2090 | |
| 2095 | | Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` |
| 2096 | 2091 | |
| 2097 | | * :class:`~django.contrib.auth.forms.AdminPasswordChangeForm` |
| | 2092 | If your custom user model is a simple subclass of |
| | 2093 | :class:`~django.contrib.auth.models.AbstractUser`, then you can extend the forms |
| | 2094 | in this manner:: |
| | 2095 | |
| | 2096 | from django.contrib.auth.forms import UserCreationForm |
| | 2097 | from myapp.models import CustomUser |
| 2098 | 2098 | |
| 2099 | | Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` |
| | 2099 | class CustomUserCreationForm(UserCreationForm): |
| | 2100 | class Meta(UserCreationForm.Meta): |
| | 2101 | model = CustomUser |
| 2100 | 2102 | |
| 2101 | 2103 | |
| 2102 | 2104 | Custom users and django.contrib.admin |