summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorTom Forbes <tom@tomforb.es>2020-07-12 13:59:57 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-12-15 11:25:46 +0100
commitb5e12d490af3debca8c55ab3c1698189fdedbbdb (patch)
tree5fe3005ac567f3addf78b81ae033191e2fa642f4 /tests
parentb960e4ed722a04a9db0d35293f76e253eedf9126 (diff)
Fixed #31007 -- Allowed specifying type of auto-created primary keys.
This also changes the default type of auto-created primary keys for new apps and projects to BigAutoField.
Diffstat (limited to 'tests')
-rw-r--r--tests/admin_scripts/tests.py15
-rw-r--r--tests/apps/apps.py5
-rw-r--r--tests/apps/tests.py28
-rw-r--r--tests/check_framework/apps.py10
-rw-r--r--tests/check_framework/test_model_checks.py57
-rw-r--r--tests/model_options/apps.py25
-rw-r--r--tests/model_options/test_default_pk.py101
-rw-r--r--tests/test_sqlite.py2
8 files changed, 241 insertions, 2 deletions
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index a82f5be5ed..7a38306d17 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -61,6 +61,7 @@ class AdminScriptTestCase(SimpleTestCase):
settings_file.write("%s\n" % extra)
exports = [
'DATABASES',
+ 'DEFAULT_AUTO_FIELD',
'ROOT_URLCONF',
'SECRET_KEY',
]
@@ -2188,6 +2189,20 @@ class StartApp(AdminScriptTestCase):
"won't replace conflicting files."
)
+ def test_template(self):
+ out, err = self.run_django_admin(['startapp', 'new_app'])
+ self.assertNoOutput(err)
+ app_path = os.path.join(self.test_dir, 'new_app')
+ self.assertIs(os.path.exists(app_path), True)
+ with open(os.path.join(app_path, 'apps.py')) as f:
+ content = f.read()
+ self.assertIn('class NewAppConfig(AppConfig)', content)
+ self.assertIn(
+ "default_auto_field = 'django.db.models.BigAutoField'",
+ content,
+ )
+ self.assertIn("name = 'new_app'", content)
+
class DiffSettings(AdminScriptTestCase):
"""Tests for diffsettings management command."""
diff --git a/tests/apps/apps.py b/tests/apps/apps.py
index d322b28f2b..efd2983779 100644
--- a/tests/apps/apps.py
+++ b/tests/apps/apps.py
@@ -31,3 +31,8 @@ class PlainAppsConfig(AppConfig):
class RelabeledAppsConfig(AppConfig):
name = 'apps'
label = 'relabeled'
+
+
+class ModelPKAppsConfig(AppConfig):
+ name = 'apps'
+ default_auto_field = 'django.db.models.BigAutoField'
diff --git a/tests/apps/tests.py b/tests/apps/tests.py
index 26d135f244..0e1f918bcc 100644
--- a/tests/apps/tests.py
+++ b/tests/apps/tests.py
@@ -102,8 +102,8 @@ class AppsTests(SimpleTestCase):
def test_no_such_app_config_with_choices(self):
msg = (
"Module 'apps.apps' does not contain a 'NoSuchConfig' class. "
- "Choices are: 'BadConfig', 'MyAdmin', 'MyAuth', 'NoSuchApp', "
- "'PlainAppsConfig', 'RelabeledAppsConfig'."
+ "Choices are: 'BadConfig', 'ModelPKAppsConfig', 'MyAdmin', "
+ "'MyAuth', 'NoSuchApp', 'PlainAppsConfig', 'RelabeledAppsConfig'."
)
with self.assertRaisesMessage(ImportError, msg):
with self.settings(INSTALLED_APPS=['apps.apps.NoSuchConfig']):
@@ -436,6 +436,30 @@ class AppConfigTests(SimpleTestCase):
ac = AppConfig('label', Stub(__path__=['a']))
self.assertEqual(repr(ac), '<AppConfig: label>')
+ @override_settings(
+ INSTALLED_APPS=['apps.apps.ModelPKAppsConfig'],
+ DEFAULT_AUTO_FIELD='django.db.models.SmallAutoField',
+ )
+ def test_app_default_auto_field(self):
+ apps_config = apps.get_app_config('apps')
+ self.assertEqual(
+ apps_config.default_auto_field,
+ 'django.db.models.BigAutoField',
+ )
+ self.assertIs(apps_config._is_default_auto_field_overridden, True)
+
+ @override_settings(
+ INSTALLED_APPS=['apps.apps.PlainAppsConfig'],
+ DEFAULT_AUTO_FIELD='django.db.models.SmallAutoField',
+ )
+ def test_default_auto_field_setting(self):
+ apps_config = apps.get_app_config('apps')
+ self.assertEqual(
+ apps_config.default_auto_field,
+ 'django.db.models.SmallAutoField',
+ )
+ self.assertIs(apps_config._is_default_auto_field_overridden, False)
+
class NamespacePackageAppTests(SimpleTestCase):
# We need nsapp to be top-level so our multiple-paths tests can add another
diff --git a/tests/check_framework/apps.py b/tests/check_framework/apps.py
new file mode 100644
index 0000000000..c57994f722
--- /dev/null
+++ b/tests/check_framework/apps.py
@@ -0,0 +1,10 @@
+from django.apps import AppConfig
+
+
+class CheckDefaultPKConfig(AppConfig):
+ name = 'check_framework'
+
+
+class CheckPKConfig(AppConfig):
+ name = 'check_framework'
+ default_auto_field = 'django.db.models.BigAutoField'
diff --git a/tests/check_framework/test_model_checks.py b/tests/check_framework/test_model_checks.py
index ce2d73fa20..d4342ada07 100644
--- a/tests/check_framework/test_model_checks.py
+++ b/tests/check_framework/test_model_checks.py
@@ -1,3 +1,5 @@
+from unittest import mock
+
from django.core import checks
from django.core.checks import Error, Warning
from django.db import models
@@ -358,3 +360,58 @@ class ConstraintNameTests(TestCase):
constraints = [constraint]
self.assertEqual(checks.run_checks(app_configs=apps.get_app_configs()), [])
+
+
+def mocked_is_overridden(self, setting):
+ # Force treating DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' as a not
+ # overridden setting.
+ return (
+ setting != 'DEFAULT_AUTO_FIELD' or
+ self.DEFAULT_AUTO_FIELD != 'django.db.models.AutoField'
+ )
+
+
+@mock.patch('django.conf.UserSettingsHolder.is_overridden', mocked_is_overridden)
+@override_settings(DEFAULT_AUTO_FIELD='django.db.models.AutoField')
+@isolate_apps('check_framework.apps.CheckDefaultPKConfig', attr_name='apps')
+@override_system_checks([checks.model_checks.check_all_models])
+class ModelDefaultAutoFieldTests(SimpleTestCase):
+ def test_auto_created_pk(self):
+ class Model(models.Model):
+ pass
+
+ self.assertEqual(checks.run_checks(app_configs=self.apps.get_app_configs()), [
+ Warning(
+ "Auto-created primary key used when not defining a primary "
+ "key type, by default 'django.db.models.AutoField'.",
+ hint=(
+ "Configure the DEFAULT_AUTO_FIELD setting or the "
+ "CheckDefaultPKConfig.default_auto_field attribute to "
+ "point to a subclass of AutoField, e.g. "
+ "'django.db.models.BigAutoField'."
+ ),
+ obj=Model,
+ id='models.W042',
+ ),
+ ])
+
+ @override_settings(DEFAULT_AUTO_FIELD='django.db.models.BigAutoField')
+ def test_default_auto_field_setting(self):
+ class Model(models.Model):
+ pass
+
+ self.assertEqual(checks.run_checks(app_configs=self.apps.get_app_configs()), [])
+
+ def test_explicit_pk(self):
+ class Model(models.Model):
+ id = models.BigAutoField(primary_key=True)
+
+ self.assertEqual(checks.run_checks(app_configs=self.apps.get_app_configs()), [])
+
+ @isolate_apps('check_framework.apps.CheckPKConfig', kwarg_name='apps')
+ def test_app_default_auto_field(self, apps):
+ class ModelWithPkViaAppConfig(models.Model):
+ class Meta:
+ app_label = 'check_framework.apps.CheckPKConfig'
+
+ self.assertEqual(checks.run_checks(app_configs=apps.get_app_configs()), [])
diff --git a/tests/model_options/apps.py b/tests/model_options/apps.py
new file mode 100644
index 0000000000..be2250fe7a
--- /dev/null
+++ b/tests/model_options/apps.py
@@ -0,0 +1,25 @@
+from django.apps import AppConfig
+
+
+class ModelDefaultPKConfig(AppConfig):
+ name = 'model_options'
+
+
+class ModelPKConfig(AppConfig):
+ name = 'model_options'
+ default_auto_field = 'django.db.models.SmallAutoField'
+
+
+class ModelPKNonAutoConfig(AppConfig):
+ name = 'model_options'
+ default_auto_field = 'django.db.models.TextField'
+
+
+class ModelPKNoneConfig(AppConfig):
+ name = 'model_options'
+ default_auto_field = None
+
+
+class ModelPKNonexistentConfig(AppConfig):
+ name = 'model_options'
+ default_auto_field = 'django.db.models.NonexistentAutoField'
diff --git a/tests/model_options/test_default_pk.py b/tests/model_options/test_default_pk.py
new file mode 100644
index 0000000000..b678848916
--- /dev/null
+++ b/tests/model_options/test_default_pk.py
@@ -0,0 +1,101 @@
+from django.core.exceptions import ImproperlyConfigured
+from django.db import models
+from django.test import SimpleTestCase, override_settings
+from django.test.utils import isolate_apps
+
+
+@isolate_apps('model_options')
+class TestDefaultPK(SimpleTestCase):
+ @override_settings(DEFAULT_AUTO_FIELD='django.db.models.NonexistentAutoField')
+ def test_default_auto_field_setting_nonexistent(self):
+ msg = (
+ "DEFAULT_AUTO_FIELD refers to the module "
+ "'django.db.models.NonexistentAutoField' that could not be "
+ "imported."
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
+ class Model(models.Model):
+ pass
+
+ @isolate_apps('model_options.apps.ModelPKNonexistentConfig')
+ def test_app_default_auto_field_nonexistent(self):
+ msg = (
+ "model_options.apps.ModelPKNonexistentConfig.default_auto_field "
+ "refers to the module 'django.db.models.NonexistentAutoField' "
+ "that could not be imported."
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
+ class Model(models.Model):
+ pass
+
+ @override_settings(DEFAULT_AUTO_FIELD='django.db.models.TextField')
+ def test_default_auto_field_setting_non_auto(self):
+ msg = (
+ "Primary key 'django.db.models.TextField' referred by "
+ "DEFAULT_AUTO_FIELD must subclass AutoField."
+ )
+ with self.assertRaisesMessage(ValueError, msg):
+ class Model(models.Model):
+ pass
+
+ @isolate_apps('model_options.apps.ModelPKNonAutoConfig')
+ def test_app_default_auto_field_non_auto(self):
+ msg = (
+ "Primary key 'django.db.models.TextField' referred by "
+ "model_options.apps.ModelPKNonAutoConfig.default_auto_field must "
+ "subclass AutoField."
+ )
+ with self.assertRaisesMessage(ValueError, msg):
+ class Model(models.Model):
+ pass
+
+ @override_settings(DEFAULT_AUTO_FIELD=None)
+ def test_default_auto_field_setting_none(self):
+ msg = 'DEFAULT_AUTO_FIELD must not be empty.'
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
+ class Model(models.Model):
+ pass
+
+ @isolate_apps('model_options.apps.ModelPKNoneConfig')
+ def test_app_default_auto_field_none(self):
+ msg = (
+ 'model_options.apps.ModelPKNoneConfig.default_auto_field must not '
+ 'be empty.'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
+ class Model(models.Model):
+ pass
+
+ @isolate_apps('model_options.apps.ModelDefaultPKConfig')
+ @override_settings(DEFAULT_AUTO_FIELD='django.db.models.SmallAutoField')
+ def test_default_auto_field_setting(self):
+ class Model(models.Model):
+ pass
+
+ self.assertIsInstance(Model._meta.pk, models.SmallAutoField)
+
+ @isolate_apps('model_options.apps.ModelPKConfig')
+ @override_settings(DEFAULT_AUTO_FIELD='django.db.models.AutoField')
+ def test_app_default_auto_field(self):
+ class Model(models.Model):
+ pass
+
+ self.assertIsInstance(Model._meta.pk, models.SmallAutoField)
+
+ @isolate_apps('model_options.apps.ModelDefaultPKConfig')
+ @override_settings(DEFAULT_AUTO_FIELD='django.db.models.SmallAutoField')
+ def test_m2m_default_auto_field_setting(self):
+ class M2MModel(models.Model):
+ m2m = models.ManyToManyField('self')
+
+ m2m_pk = M2MModel._meta.get_field('m2m').remote_field.through._meta.pk
+ self.assertIsInstance(m2m_pk, models.SmallAutoField)
+
+ @isolate_apps('model_options.apps.ModelPKConfig')
+ @override_settings(DEFAULT_AUTO_FIELD='django.db.models.AutoField')
+ def test_m2m_app_default_auto_field(self):
+ class M2MModel(models.Model):
+ m2m = models.ManyToManyField('self')
+
+ m2m_pk = M2MModel._meta.get_field('m2m').remote_field.through._meta.pk
+ self.assertIsInstance(m2m_pk, models.SmallAutoField)
diff --git a/tests/test_sqlite.py b/tests/test_sqlite.py
index f1b65f7d01..099f37e56d 100644
--- a/tests/test_sqlite.py
+++ b/tests/test_sqlite.py
@@ -27,3 +27,5 @@ SECRET_KEY = "django_tests_secret_key"
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.MD5PasswordHasher',
]
+
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'