Refs #19353 -- Added tests for using custom user models with built-in auth forms.

Also updated topics/auth/customizing.txt to reflect that subclasses of
UserCreationForm and UserChangeForm can be used with custom user models.

Thanks Baptiste Mispelon for the initial documentation.
This commit is contained in:
Berker Peksag 2016-02-14 17:30:01 +02:00 committed by Tim Graham
parent d4dc775620
commit f0425c7260
2 changed files with 67 additions and 34 deletions

View File

@ -733,47 +733,45 @@ the "Model design considerations" note of :ref:`specifying-custom-user-model`.
Custom users and the built-in auth forms
----------------------------------------
As you may expect, built-in Django's :ref:`forms <built-in-auth-forms>` and
:ref:`views <built-in-auth-views>` make certain assumptions about the user
model that they are working with.
Django's built-in :ref:`forms <built-in-auth-forms>` and :ref:`views
<built-in-auth-views>` make certain assumptions about the user model that they
are working with.
If your user model doesn't follow the same assumptions, it may be necessary to define
a replacement form, and pass that form in as part of the configuration of the
auth views.
* :class:`~django.contrib.auth.forms.UserCreationForm`
Depends on the :class:`~django.contrib.auth.models.User` model.
Must be re-written for any custom user model.
* :class:`~django.contrib.auth.forms.UserChangeForm`
Depends on the :class:`~django.contrib.auth.models.User` model.
Must be re-written for any custom user model.
* :class:`~django.contrib.auth.forms.AuthenticationForm`
Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser`,
and will adapt to use the field defined in ``USERNAME_FIELD``.
* :class:`~django.contrib.auth.forms.PasswordResetForm`
Assumes that the user model has a field named ``email`` that can be used to
identify the user and a boolean field named ``is_active`` to prevent
password resets for inactive users.
The following forms are compatible with any subclass of
:class:`~django.contrib.auth.models.AbstractBaseUser`:
* :class:`~django.contrib.auth.forms.AuthenticationForm`: Uses the username
field specified by :attr:`~models.CustomUser.USERNAME_FIELD`.
* :class:`~django.contrib.auth.forms.SetPasswordForm`
Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser`
* :class:`~django.contrib.auth.forms.PasswordChangeForm`
Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser`
* :class:`~django.contrib.auth.forms.AdminPasswordChangeForm`
Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser`
The following forms make assumptions about the user model and can be used as-is
if those assumptions are met:
* :class:`~django.contrib.auth.forms.PasswordResetForm`: Assumes that the user
model has a field named ``email`` that can be used to identify the user and a
boolean field named ``is_active`` to prevent password resets for inactive
users.
Finally, the following forms are tied to
:class:`~django.contrib.auth.models.User` and need to be rewritten or extended
to work with a custom user model:
* :class:`~django.contrib.auth.forms.UserCreationForm`
* :class:`~django.contrib.auth.forms.UserChangeForm`
If your custom user model is a simple subclass of ``AbstractUser``, then you
can extend these forms in this manner::
from django.contrib.auth.forms import UserCreationForm
from myapp.models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = UserCreationForm.Meta.fields + ('custom_field',)
Custom users and :mod:`django.contrib.admin`
--------------------------------------------

View File

@ -1,5 +1,6 @@
from __future__ import unicode_literals
import datetime
import re
from django import forms
@ -19,6 +20,7 @@ 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 ExtensionUser
from .settings import AUTH_TEMPLATES
@ -122,6 +124,21 @@ class UserCreationFormTest(TestDataMixin, TestCase):
form['password2'].errors
)
def test_custom_form(self):
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = ExtensionUser
fields = UserCreationForm.Meta.fields + ('date_of_birth',)
data = {
'username': 'testclient',
'password1': 'testclient',
'password2': 'testclient',
'date_of_birth': '1988-02-24',
}
form = CustomUserCreationForm(data)
self.assertTrue(form.is_valid())
class AuthenticationFormTest(TestDataMixin, TestCase):
@ -407,6 +424,24 @@ class UserChangeFormTest(TestDataMixin, TestCase):
# value to render correctly
self.assertEqual(form.initial['password'], form['password'].value())
def test_custom_form(self):
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = ExtensionUser
fields = ('username', 'password', 'date_of_birth',)
user = User.objects.get(username='testclient')
data = {
'username': 'testclient',
'password': 'testclient',
'date_of_birth': '1998-02-24',
}
form = CustomUserChangeForm(data, instance=user)
self.assertTrue(form.is_valid())
form.save()
self.assertEqual(form.cleaned_data['username'], 'testclient')
self.assertEqual(form.cleaned_data['date_of_birth'], datetime.date(1998, 2, 24))
@override_settings(TEMPLATES=AUTH_TEMPLATES)
class PasswordResetFormTest(TestDataMixin, TestCase):