From 14e34dcf8cb935454f4ce02402949d8af204fdab Mon Sep 17 00:00:00 2001 From: Mikhail Porokhovnichenko Date: Sat, 17 Feb 2018 21:00:12 +0700 Subject: [PATCH] Fixed #29132 -- Avoided connecting update_last_login() handler if User.last_login isn't a field. --- django/contrib/auth/apps.py | 5 ++++- tests/auth_tests/models/__init__.py | 3 ++- tests/auth_tests/models/with_last_login_attr.py | 5 +++++ tests/auth_tests/test_signals.py | 8 +++++++- 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 tests/auth_tests/models/with_last_login_attr.py diff --git a/django/contrib/auth/apps.py b/django/contrib/auth/apps.py index 18f149659b..b9d271bb1f 100644 --- a/django/contrib/auth/apps.py +++ b/django/contrib/auth/apps.py @@ -1,5 +1,6 @@ from django.apps import AppConfig from django.core import checks +from django.db.models.query_utils import DeferredAttribute from django.db.models.signals import post_migrate from django.utils.translation import gettext_lazy as _ @@ -18,7 +19,9 @@ class AuthConfig(AppConfig): create_permissions, dispatch_uid="django.contrib.auth.management.create_permissions" ) - if hasattr(get_user_model(), 'last_login'): + last_login_field = getattr(get_user_model(), 'last_login', None) + # Register the handler only if UserModel.last_login is a field. + if isinstance(last_login_field, DeferredAttribute): 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) diff --git a/tests/auth_tests/models/__init__.py b/tests/auth_tests/models/__init__.py index af58cb7118..e5e38a1e2e 100644 --- a/tests/auth_tests/models/__init__.py +++ b/tests/auth_tests/models/__init__.py @@ -8,10 +8,11 @@ from .minimal import MinimalUser from .uuid_pk import UUIDUser from .with_foreign_key import CustomUserWithFK, Email from .with_integer_username import IntegerUsernameUser +from .with_last_login_attr import UserWithDisabledLastLoginField __all__ = ( 'CustomUser', 'CustomUserWithoutIsActiveField', 'CustomPermissionsUser', 'CustomUserWithFK', 'Email', 'ExtensionUser', 'IsActiveTestUser1', 'MinimalUser', 'UUIDUser', 'CustomUserNonUniqueUsername', - 'IntegerUsernameUser', + 'IntegerUsernameUser', 'UserWithDisabledLastLoginField', ) diff --git a/tests/auth_tests/models/with_last_login_attr.py b/tests/auth_tests/models/with_last_login_attr.py new file mode 100644 index 0000000000..d83adb1452 --- /dev/null +++ b/tests/auth_tests/models/with_last_login_attr.py @@ -0,0 +1,5 @@ +from django.contrib.auth.base_user import AbstractBaseUser + + +class UserWithDisabledLastLoginField(AbstractBaseUser): + last_login = None diff --git a/tests/auth_tests/test_signals.py b/tests/auth_tests/test_signals.py index ab2b792de9..93b6c82366 100644 --- a/tests/auth_tests/test_signals.py +++ b/tests/auth_tests/test_signals.py @@ -5,7 +5,7 @@ from django.core.exceptions import FieldDoesNotExist from django.test import TestCase, override_settings from django.test.client import RequestFactory -from .models import MinimalUser +from .models import MinimalUser, UserWithDisabledLastLoginField @override_settings(ROOT_URLCONF='auth_tests.urls') @@ -101,6 +101,12 @@ class SignalTestCase(TestCase): apps.get_app_config('auth').ready() self.assertEqual(signals.user_logged_in.receivers, []) + # last_login is a property whose value is None. + self.assertIsNone(UserWithDisabledLastLoginField().last_login) + with self.settings(AUTH_USER_MODEL='auth_tests.UserWithDisabledLastLoginField'): + 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)