Fixed #7220 -- Allowed AbstractBaseUser.last_login to be null.

Thanks veena for the suggestion and Simon Charette and Kévin Etienne for reviews.
This commit is contained in:
Tim Graham 2014-07-29 08:56:00 -04:00
parent 1a31d9ef91
commit a2479f46f3
6 changed files with 55 additions and 5 deletions

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('auth', '0004_alter_user_username_opts'),
]
operations = [
migrations.AlterField(
model_name='user',
name='last_login',
field=models.DateTimeField(null=True, verbose_name='last login', blank=True),
),
]

View File

@ -172,7 +172,7 @@ class UserManager(BaseUserManager):
email = self.normalize_email(email)
user = self.model(username=username, email=email,
is_staff=is_staff, is_active=True,
is_superuser=is_superuser, last_login=now,
is_superuser=is_superuser,
date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
@ -190,7 +190,7 @@ class UserManager(BaseUserManager):
@python_2_unicode_compatible
class AbstractBaseUser(models.Model):
password = models.CharField(_('password'), max_length=128)
last_login = models.DateTimeField(_('last login'), default=timezone.now)
last_login = models.DateTimeField(_('last login'), blank=True, null=True)
is_active = True

View File

@ -156,6 +156,13 @@ class AbstractUserTestCase(TestCase):
self.assertEqual(message.from_email, "from@domain.com")
self.assertEqual(message.to, [abstract_user.email])
def test_last_login_default(self):
user1 = User.objects.create(username='user1')
self.assertIsNone(user1.last_login)
user2 = User.objects.create_user(username='user2')
self.assertIsNone(user2.last_login)
class IsActiveTestCase(TestCase):
"""

View File

@ -56,7 +56,7 @@ class PasswordResetTokenGenerator(object):
key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"
# Ensure results are consistent across DB backends
login_timestamp = user.last_login.replace(microsecond=0, tzinfo=None)
login_timestamp = '' if user.last_login is None else user.last_login.replace(microsecond=0, tzinfo=None)
value = (six.text_type(user.pk) + user.password +
six.text_type(login_timestamp) + six.text_type(timestamp))

View File

@ -81,8 +81,12 @@ Fields
.. attribute:: last_login
A datetime of the user's last login. Is set to the current date/time by
default.
A datetime of the user's last login.
.. versionchanged:: 1.8
This field will be ``null`` if the user has never logged in.
Previously it was set to the current date/time by default.
.. attribute:: date_joined

View File

@ -407,6 +407,26 @@ officially supports.
This also includes dropping support for PostGIS 1.3 and 1.4 as these versions
are not supported on versions of PostgreSQL later than 8.4.
``AbstractUser.last_login`` allows null values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The :attr:`AbstractUser.last_login <django.contrib.auth.models.User.last_login>`
field now allows null values. Previously, it defaulted to the time when the user
was created which was misleading if the user never logged in. Please run the
database migration. If your custom user inherits from ``AbstractUser`` and you
wish to set ``last_login`` to ``NULL`` for users who haven't logged in, you can
run this query::
from django.db import models
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractBaseUser
UserModel = get_user_model()
if issubclass(UserModel, AbstractBaseUser):
UserModel._default_manager.filter(
last_login=models.F('date_joined')
).update(last_login=None)
Miscellaneous
~~~~~~~~~~~~~