When adding a trigger to a default many-to-many "through" model (e.g. User.groups.through), running manage.py test raises InvalidBasesError if there is a secondary database that has "TEST": { "MIGRATE": False } configured.
Steps to reproduce
# settings.py
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "django_demo_app",
...
},
"timescale": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "django_demo_app",
...
"MIGRATE": False,
"TEST": {
"MIGRATE": False,
}
},
}
# models.py
from django.contrib.auth.models import User
import pgtrigger
class UserGroupTriggers(User.groups.through):
class Meta:
proxy = True
triggers = [
pgtrigger.Protect(
name="protect_managed_groupprops_delete",
operation=pgtrigger.Delete,
),
]
When python manage.py test is executed, a django.db.migrations.exceptions.InvalidBasesError is thrown:
Click to view Stacktrace
Found 1 test(s).
Creating test database for alias 'default'...
Got an error creating the test database: database "test_django_demo_app" already exists
Destroying old test database for alias 'default'...
Creating test database for alias 'timescale'...
Got an error creating the test database: database "test_django_demo_app" already exists
Destroying old test database for alias 'timescale'...
Traceback (most recent call last):
File "/Users/daniel/tmp/demo/./manage.py", line 23, in
main()
File "/Users/daniel/tmp/demo/./manage.py", line 19, in main
execute_from_command_line(sys.argv)
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line
utility.execute()
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 437, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/commands/test.py", line 24, in run_from_argv
super().run_from_argv(argv)
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/base.py", line 420, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/base.py", line 464, in execute
output = self.handle(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/commands/test.py", line 63, in handle
failures = test_runner.run_tests(test_labels)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/test/runner.py", line 1127, in run_tests
old_config = self.setup_databases(
^^^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/test/runner.py", line 1026, in setup_databases
return _setup_databases(
^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/test/utils.py", line 207, in setup_databases
connection.creation.create_test_db(
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/db/backends/base/creation.py", line 85, in create_test_db
call_command(
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 195, in call_command
return command.execute(*args, **defaults)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/base.py", line 464, in execute
output = self.handle(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/base.py", line 111, in wrapper
res = handle_func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/commands/migrate.py", line 300, in handle
pre_migrate_apps = pre_migrate_state.apps
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/utils/functional.py", line 47, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/db/migrations/state.py", line 591, in apps
return StateApps(self.real_apps, self.models)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/db/migrations/state.py", line 652, in __init__
self.render_multiple([*models.values(), *self.real_models])
File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/db/migrations/state.py", line 694, in render_multiple
raise InvalidBasesError(
django.db.migrations.exceptions.InvalidBasesError: Cannot resolve bases for []
This can happen if you are inheriting models from an app with migrations (e.g. contrib.auth)
in an app with no migrations; see https://docs.djangoproject.com/en/6.0/topics/migrations/#dependencies for more
I looked a little bit into why this error occurs and as far as I understand, it might be from django/db/backends/base/creation.py in create_test_db. It explicitly sets settings.MIGRATION_MODULES to None for all installed apps: Link to source code
This might be a issue with django itself, but I still wanted to create an issue here first, since the M2M through-tables pattern is in the django-pgtrigger documentation.
Environment:
Python: 3.12.9
Django: 6.0.3
django-pgtrigger: 4.17.0
When adding a trigger to a default many-to-many "through" model (e.g.
User.groups.through), running manage.py test raisesInvalidBasesErrorif there is a secondary database that has"TEST": { "MIGRATE": False }configured.Steps to reproduce
When
python manage.py testis executed, adjango.db.migrations.exceptions.InvalidBasesErroris thrown:Click to view Stacktrace
Found 1 test(s). Creating test database for alias 'default'... Got an error creating the test database: database "test_django_demo_app" already exists Destroying old test database for alias 'default'... Creating test database for alias 'timescale'... Got an error creating the test database: database "test_django_demo_app" already exists Destroying old test database for alias 'timescale'... Traceback (most recent call last): File "/Users/daniel/tmp/demo/./manage.py", line 23, in main() File "/Users/daniel/tmp/demo/./manage.py", line 19, in main execute_from_command_line(sys.argv) File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line utility.execute() File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 437, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/commands/test.py", line 24, in run_from_argv super().run_from_argv(argv) File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/base.py", line 420, in run_from_argv self.execute(*args, **cmd_options) File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/base.py", line 464, in execute output = self.handle(*args, **options) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/commands/test.py", line 63, in handle failures = test_runner.run_tests(test_labels) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/test/runner.py", line 1127, in run_tests old_config = self.setup_databases( ^^^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/test/runner.py", line 1026, in setup_databases return _setup_databases( ^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/test/utils.py", line 207, in setup_databases connection.creation.create_test_db( File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/db/backends/base/creation.py", line 85, in create_test_db call_command( File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 195, in call_command return command.execute(*args, **defaults) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/base.py", line 464, in execute output = self.handle(*args, **options) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/base.py", line 111, in wrapper res = handle_func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/core/management/commands/migrate.py", line 300, in handle pre_migrate_apps = pre_migrate_state.apps ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/utils/functional.py", line 47, in __get__ res = instance.__dict__[self.name] = self.func(instance) ^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/db/migrations/state.py", line 591, in apps return StateApps(self.real_apps, self.models) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/db/migrations/state.py", line 652, in __init__ self.render_multiple([*models.values(), *self.real_models]) File "/Users/daniel/tmp/demo/.venv/lib/python3.12/site-packages/django/db/migrations/state.py", line 694, in render_multiple raise InvalidBasesError( django.db.migrations.exceptions.InvalidBasesError: Cannot resolve bases for [] This can happen if you are inheriting models from an app with migrations (e.g. contrib.auth) in an app with no migrations; see https://docs.djangoproject.com/en/6.0/topics/migrations/#dependencies for moreI looked a little bit into why this error occurs and as far as I understand, it might be from
django/db/backends/base/creation.pyincreate_test_db. It explicitly setssettings.MIGRATION_MODULEStoNonefor all installed apps: Link to source codeThis might be a issue with django itself, but I still wanted to create an issue here first, since the M2M through-tables pattern is in the django-pgtrigger documentation.
Environment:
Python: 3.12.9
Django: 6.0.3
django-pgtrigger: 4.17.0