Skip to content

Commit

Permalink
Fixed #26719 -- Normalized email in AbstractUser.clean().
Browse files Browse the repository at this point in the history
  • Loading branch information
Bang Dao + Tam Huynh authored and timgraham committed Jun 24, 2016
1 parent 7e303d1 commit 09119df
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 1 deletion.
4 changes: 4 additions & 0 deletions django/contrib/auth/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,10 @@ class Meta:
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.
Expand Down
5 changes: 5 additions & 0 deletions docs/releases/1.11.txt
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,11 @@ Miscellaneous
<django.db.models.Model.validate_unique>` 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
Expand Down
14 changes: 13 additions & 1 deletion docs/topics/auth/customizing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions tests/auth_tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ def test_last_login_default(self):
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.
Expand Down

0 comments on commit 09119df

Please sign in to comment.