From 09119dff14ad24d53ac0273e5cd2de24de0b0d81 Mon Sep 17 00:00:00 2001 From: Bang Dao + Tam Huynh Date: Thu, 16 Jun 2016 17:06:59 +0700 Subject: [PATCH] Fixed #26719 -- Normalized email in AbstractUser.clean(). --- django/contrib/auth/models.py | 4 ++++ docs/releases/1.11.txt | 5 +++++ docs/topics/auth/customizing.txt | 14 +++++++++++++- tests/auth_tests/test_models.py | 5 +++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 48125463402..725563424a0 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -344,6 +344,10 @@ class AbstractUser(AbstractBaseUser, PermissionsMixin): verbose_name_plural = _('users') abstract = True + def clean(self): + super(AbstractUser, self).clean() + self.email = self.__class__.objects.normalize_email(self.email) + def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt index ca54d0b223a..e5dcc47e248 100644 --- a/docs/releases/1.11.txt +++ b/docs/releases/1.11.txt @@ -293,6 +293,11 @@ Miscellaneous ` no longer checks empty strings for uniqueness as the database interprets the value as ``NULL``. +* If you subclass :class:`.AbstractUser` and override ``clean()``, be sure it + calls ``super()``. :meth:`.BaseUserManager.normalize_email` is called in a + new :meth:`.AbstractUser.clean` method so that normalization is applied in + cases like model form validation. + .. _deprecated-features-1.11: Features deprecated in 1.11 diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt index 75dd4160d03..db18bfb8c20 100644 --- a/docs/topics/auth/customizing.txt +++ b/docs/topics/auth/customizing.txt @@ -692,6 +692,18 @@ The following attributes and methods are available on any subclass of Returns an HMAC of the password field. Used for :ref:`session-invalidation-on-password-change`. +:class:`~models.AbstractUser` subclasses :class:`~models.AbstractBaseUser`: + +.. class:: models.AbstractUser + + .. method:: clean() + + .. versionadded:: 1.11 + + Normalizes the email by calling + :meth:`.BaseUserManager.normalize_email`. If you override this method, + be sure to call ``super()`` to retain the normalization. + You should also define a custom manager for your ``User`` model. If your ``User`` model defines ``username``, ``email``, ``is_staff``, ``is_active``, ``is_superuser``, ``last_login``, and ``date_joined`` fields the same as @@ -759,7 +771,7 @@ Extending Django's default ``User`` If you're entirely happy with Django's :class:`~django.contrib.auth.models.User` model and you just want to add some additional profile information, you could -simply subclass ``django.contrib.auth.models.AbstractUser`` and add your +simply subclass :class:`django.contrib.auth.models.AbstractUser` and add your custom profile fields, although we'd recommend a separate model as described in the "Model design considerations" note of :ref:`specifying-custom-user-model`. ``AbstractUser`` provides the full implementation of the default diff --git a/tests/auth_tests/test_models.py b/tests/auth_tests/test_models.py index 7967306c43e..5f66a481412 100644 --- a/tests/auth_tests/test_models.py +++ b/tests/auth_tests/test_models.py @@ -194,6 +194,11 @@ class AbstractUserTestCase(TestCase): user2 = User.objects.create_user(username='user2') self.assertIsNone(user2.last_login) + def test_user_clean_normalize_email(self): + user = User(username='user', password='foo', email='foo@BAR.com') + user.clean() + self.assertEqual(user.email, 'foo@bar.com') + def test_user_double_save(self): """ Calling user.save() twice should trigger password_changed() once.