summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Lewandowski <linus@lew21.net>2017-05-27 14:35:02 +0200
committerTim Graham <timograham@gmail.com>2017-05-29 17:31:18 -0400
commiteedc88bd4a8468c2a0daa8346c9b57183dd77782 (patch)
tree6f6532ce30fcd862759e6e1cd8557270f387568d
parente84034b37a690889a2f77d85f85beebbd165598b (diff)
Fixed #26823 -- Prevented update_last_login signal receiver from crashing if User model doesn't have last_login field.
-rw-r--r--django/contrib/auth/apps.py5
-rw-r--r--django/contrib/auth/models.py4
-rw-r--r--tests/auth_tests/models/__init__.py4
-rw-r--r--tests/auth_tests/models/minimal.py6
-rw-r--r--tests/auth_tests/test_signals.py24
5 files changed, 38 insertions, 5 deletions
diff --git a/django/contrib/auth/apps.py b/django/contrib/auth/apps.py
index 83790007d9..18f149659b 100644
--- a/django/contrib/auth/apps.py
+++ b/django/contrib/auth/apps.py
@@ -3,8 +3,10 @@ from django.core import checks
from django.db.models.signals import post_migrate
from django.utils.translation import gettext_lazy as _
+from . import get_user_model
from .checks import check_models_permissions, check_user_model
from .management import create_permissions
+from .signals import user_logged_in
class AuthConfig(AppConfig):
@@ -16,5 +18,8 @@ class AuthConfig(AppConfig):
create_permissions,
dispatch_uid="django.contrib.auth.management.create_permissions"
)
+ if hasattr(get_user_model(), 'last_login'):
+ from .models import update_last_login
+ user_logged_in.connect(update_last_login, dispatch_uid='update_last_login')
checks.register(check_user_model, checks.Tags.models)
checks.register(check_models_permissions, checks.Tags.models)
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index dad7d288c5..d931277c66 100644
--- a/django/contrib/auth/models.py
+++ b/django/contrib/auth/models.py
@@ -1,6 +1,5 @@
from django.contrib import auth
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
-from django.contrib.auth.signals import user_logged_in
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.core.mail import send_mail
@@ -21,9 +20,6 @@ def update_last_login(sender, user, **kwargs):
user.save(update_fields=['last_login'])
-user_logged_in.connect(update_last_login)
-
-
class PermissionManager(models.Manager):
use_in_migrations = True
diff --git a/tests/auth_tests/models/__init__.py b/tests/auth_tests/models/__init__.py
index 8b8cb69ef3..af58cb7118 100644
--- a/tests/auth_tests/models/__init__.py
+++ b/tests/auth_tests/models/__init__.py
@@ -4,6 +4,7 @@ from .custom_user import (
)
from .invalid_models import CustomUserNonUniqueUsername
from .is_active import IsActiveTestUser1
+from .minimal import MinimalUser
from .uuid_pk import UUIDUser
from .with_foreign_key import CustomUserWithFK, Email
from .with_integer_username import IntegerUsernameUser
@@ -11,5 +12,6 @@ from .with_integer_username import IntegerUsernameUser
__all__ = (
'CustomUser', 'CustomUserWithoutIsActiveField', 'CustomPermissionsUser',
'CustomUserWithFK', 'Email', 'ExtensionUser', 'IsActiveTestUser1',
- 'UUIDUser', 'CustomUserNonUniqueUsername', 'IntegerUsernameUser'
+ 'MinimalUser', 'UUIDUser', 'CustomUserNonUniqueUsername',
+ 'IntegerUsernameUser',
)
diff --git a/tests/auth_tests/models/minimal.py b/tests/auth_tests/models/minimal.py
new file mode 100644
index 0000000000..7b8931b231
--- /dev/null
+++ b/tests/auth_tests/models/minimal.py
@@ -0,0 +1,6 @@
+from django.db import models
+
+
+class MinimalUser(models.Model):
+ REQUIRED_FIELDS = ()
+ USERNAME_FIELD = 'id'
diff --git a/tests/auth_tests/test_signals.py b/tests/auth_tests/test_signals.py
index 8fb2046e1c..93a8689463 100644
--- a/tests/auth_tests/test_signals.py
+++ b/tests/auth_tests/test_signals.py
@@ -1,8 +1,12 @@
+from django.apps import apps
from django.contrib.auth import authenticate, signals
from django.contrib.auth.models import User
+from django.core.exceptions import FieldDoesNotExist
from django.test import TestCase, override_settings
from django.test.client import RequestFactory
+from .models import MinimalUser
+
@override_settings(ROOT_URLCONF='auth_tests.urls')
class SignalTestCase(TestCase):
@@ -82,3 +86,23 @@ class SignalTestCase(TestCase):
def test_failed_login_without_request(self):
authenticate(username='testclient', password='bad')
self.assertIsNone(self.login_failed[0]['request'])
+
+ def test_login_with_custom_user_without_last_login_field(self):
+ """
+ The user_logged_in signal is only registered if the user model has a
+ last_login field.
+ """
+ last_login_receivers = signals.user_logged_in.receivers
+ try:
+ signals.user_logged_in.receivers = []
+ with self.assertRaises(FieldDoesNotExist):
+ MinimalUser._meta.get_field('last_login')
+ with self.settings(AUTH_USER_MODEL='auth_tests.MinimalUser'):
+ apps.get_app_config('auth').ready()
+ self.assertEqual(signals.user_logged_in.receivers, [])
+
+ with self.settings(AUTH_USER_MODEL='auth.User'):
+ apps.get_app_config('auth').ready()
+ self.assertEqual(len(signals.user_logged_in.receivers), 1)
+ finally:
+ signals.user_logged_in.receivers = last_login_receivers