Skip to content

InvalidBasesError when using proxy model trigger pattern with a secondary DB configured with TEST.MIGRATE = False #224

Description

@pai-danielkleinridder

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions