diff --git a/django/db/models/base.py b/django/db/models/base.py index df5b0ca137..3792ffb90e 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -409,6 +409,8 @@ class Model(metaclass=ModelBase): opts = self._meta _setattr = setattr _DEFERRED = DEFERRED + if opts.abstract: + raise TypeError('Abstract models cannot be instantiated.') pre_init.send(sender=cls, args=args, kwargs=kwargs) diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt index d854c7e53f..d1e21b2868 100644 --- a/docs/releases/3.2.txt +++ b/docs/releases/3.2.txt @@ -435,6 +435,8 @@ Miscellaneous in the :class:`~django.apps.AppConfig` subclass if you need to prevent this behavior. See :ref:`whats-new-3.2` for more details. +* Instantiating an abstract model now raises ``TypeError``. + .. _deprecated-features-3.2: Features deprecated in 3.2 diff --git a/tests/auth_tests/test_models.py b/tests/auth_tests/test_models.py index 2379f68b83..5a4c5cdecd 100644 --- a/tests/auth_tests/test_models.py +++ b/tests/auth_tests/test_models.py @@ -6,7 +6,7 @@ from django.contrib.auth.backends import ModelBackend from django.contrib.auth.base_user import AbstractBaseUser from django.contrib.auth.hashers import get_hasher from django.contrib.auth.models import ( - AbstractUser, AnonymousUser, Group, Permission, User, UserManager, + AnonymousUser, Group, Permission, User, UserManager, ) from django.contrib.contenttypes.models import ContentType from django.core import mail @@ -215,8 +215,7 @@ class AbstractBaseUserTests(SimpleTestCase): self.assertEqual(username, 'iamtheΩ') # U+03A9 GREEK CAPITAL LETTER OMEGA def test_default_email(self): - user = AbstractBaseUser() - self.assertEqual(user.get_email_field_name(), 'email') + self.assertEqual(AbstractBaseUser.get_email_field_name(), 'email') def test_custom_email(self): user = CustomEmailField() @@ -233,8 +232,8 @@ class AbstractUserTestCase(TestCase): "connection": None, "html_message": None, } - abstract_user = AbstractUser(email='foo@bar.com') - abstract_user.email_user( + user = User(email='foo@bar.com') + user.email_user( subject="Subject here", message="This is a message", from_email="from@domain.com", @@ -245,7 +244,7 @@ class AbstractUserTestCase(TestCase): self.assertEqual(message.subject, "Subject here") self.assertEqual(message.body, "This is a message") self.assertEqual(message.from_email, "from@domain.com") - self.assertEqual(message.to, [abstract_user.email]) + self.assertEqual(message.to, [user.email]) def test_last_login_default(self): user1 = User.objects.create(username='user1') diff --git a/tests/model_meta/tests.py b/tests/model_meta/tests.py index ad58b336bd..32bcfbc9e6 100644 --- a/tests/model_meta/tests.py +++ b/tests/model_meta/tests.py @@ -279,10 +279,19 @@ class ParentListTests(SimpleTestCase): class PropertyNamesTests(SimpleTestCase): def test_person(self): # Instance only descriptors don't appear in _property_names. - self.assertEqual(AbstractPerson().test_instance_only_descriptor, 1) + self.assertEqual(BasePerson().test_instance_only_descriptor, 1) + with self.assertRaisesMessage(AttributeError, 'Instance only'): + AbstractPerson.test_instance_only_descriptor self.assertEqual(AbstractPerson._meta._property_names, frozenset(['pk', 'test_property'])) class ReturningFieldsTests(SimpleTestCase): def test_pk(self): self.assertEqual(Relation._meta.db_returning_fields, [Relation._meta.pk]) + + +class AbstractModelTests(SimpleTestCase): + def test_abstract_model_not_instantiated(self): + msg = 'Abstract models cannot be instantiated.' + with self.assertRaisesMessage(TypeError, msg): + AbstractPerson()