203 lines
7.9 KiB
Diff
203 lines
7.9 KiB
Diff
Let me understand the issue from the problem statement and hints:
|
|
|
|
1. **Issue**: When `TEST: {"MIGRATE": False}` is set, the test runner crashes because:
|
|
- It tries to serialize the database contents via `serialize_db_to_string()`
|
|
- But since migrations weren't run, tables like `django_admin_log` don't exist
|
|
- This causes a `ProgrammingError: relation "django_admin_log" does not exist`
|
|
|
|
2. **Root cause from hints**: When `MIGRATE` is `False`, Django should still synchronize all apps (create tables) using `run_syncdb=True`, but it currently only does this when `MIGRATE` is `True`.
|
|
|
|
3. **Fix from hints**: Run `migrate --run-syncdb` with `MIGRATION_MODULES` set to `None` for all apps, which causes Django to create tables without running actual migrations.
|
|
|
|
Let me create the patch based on the Django 3.1 code structure. Looking at the traceback:
|
|
|
|
```python
|
|
# In django/db/backends/base/creation.py, line 78
|
|
self.connection._test_serialized_contents = self.serialize_db_to_string()
|
|
```
|
|
|
|
The issue is in `create_test_db()` method. When `MIGRATE` is `False`, Django still tries to serialize the database, but the tables don't exist because migrations weren't run. The fix needs to:
|
|
1. When `MIGRATE` is `False`, still run `syncdb` to create tables (just without actual migrations)
|
|
2. This is done by setting `MIGRATION_MODULES` to `{app.label: None}` for all apps and running `migrate --run-syncdb`
|
|
|
|
Based on the traceback and hints, here's the patch for `django/db/backends/base/creation.py`:
|
|
|
|
--- a/django/db/backends/base/creation.py
|
|
+++ b/django/db/backends/base/creation.py
|
|
@@ -58,6 +58,7 @@ class BaseDatabaseCreation:
|
|
test_database_name = self._get_test_db_name()
|
|
|
|
if verbosity >= 1:
|
|
+ from django.apps import apps
|
|
action = 'Creating'
|
|
if keepdb:
|
|
action = "Using existing"
|
|
@@ -71,14 +72,28 @@ class BaseDatabaseCreation:
|
|
# We then serialize the current state of the database into a string
|
|
# and store it on the connection. This slightly horrific process is so
|
|
# people who are testing on databases without transactions or instantiate
|
|
- # a test database from a .sql script can still use TransactionTestCase.
|
|
+ # a test database from a .sql script can still use
|
|
+ # TransactionTestCase.
|
|
if serialize:
|
|
- self.connection._test_serialized_contents = self.serialize_db_to_string()
|
|
+ self.connection._test_serialized_contents = (
|
|
+ self.serialize_db_to_string()
|
|
+ )
|
|
|
|
call_command('createcachetable', database=self.connection.alias)
|
|
|
|
return test_database_name
|
|
|
|
+ def _syncdb(self, verbosity, interactive):
|
|
+ """Sync database tables without migrations."""
|
|
+ from django.apps import apps
|
|
+ from django.conf import settings
|
|
+ from django.core.management import call_command
|
|
+ migration_modules = settings.MIGRATION_MODULES
|
|
+ settings.MIGRATION_MODULES = {app.label: None for app in apps.get_app_configs()}
|
|
+ try:
|
|
+ call_command(
|
|
+ 'migrate',
|
|
+ verbosity=max(verbosity - 1, 0),
|
|
+ interactive=interactive,
|
|
+ database=self.connection.alias,
|
|
+ run_syncdb=True,
|
|
+ )
|
|
+ finally:
|
|
+ settings.MIGRATION_MODULES = migration_modules
|
|
+
|
|
def set_as_test_mirror(self, primary_settings_dict):
|
|
"""
|
|
Set this database up to be used in testing as a mirror of a primary
|
|
|
|
Wait, I need to look more carefully at the code flow. The actual issue is that when `MIGRATE` is `False`, the `_create_test_db` method doesn't run any migrations/syncdb, but the code still tries to serialize. Let me re-read the traceback.
|
|
|
|
Looking at line 69 of the traceback reference:
|
|
```python
|
|
call_command(
|
|
'migrate',
|
|
...
|
|
run_syncdb=True,
|
|
)
|
|
```
|
|
|
|
This only runs when `MIGRATE` is True. When `MIGRATE` is False, no tables are created, but serialization is still attempted.
|
|
|
|
The fix should be: when `MIGRATE` is `False`, we still need to create tables by running `migrate --run-syncdb` but with `MIGRATION_MODULES` set to disable all migrations (so it uses syncdb behavior).
|
|
|
|
--- a/django/db/backends/base/creation.py
|
|
+++ b/django/db/backends/base/creation.py
|
|
@@ -58,7 +58,9 @@ class BaseDatabaseCreation:
|
|
test_database_name = self._get_test_db_name()
|
|
|
|
if verbosity >= 1:
|
|
+ from django.apps import apps
|
|
action = 'Creating'
|
|
+ from django.conf import settings
|
|
if keepdb:
|
|
action = "Using existing"
|
|
|
|
@@ -68,6 +70,21 @@ class BaseDatabaseCreation:
|
|
interactive=False,
|
|
database=self.connection.alias,
|
|
run_syncdb=True,
|
|
)
|
|
+ else:
|
|
+ old_migration_modules = settings.MIGRATION_MODULES
|
|
+ try:
|
|
+ settings.MIGRATION_MODULES = {
|
|
+ app.label: None
|
|
+ for app in apps.get_app_configs()
|
|
+ }
|
|
+ call_command(
|
|
+ 'migrate',
|
|
+ verbosity=max(verbosity - 1, 0),
|
|
+ interactive=False,
|
|
+ database=self.connection.alias,
|
|
+ run_syncdb=True,
|
|
+ )
|
|
+ finally:
|
|
+ settings.MIGRATION_MODULES = old_migration_modules
|
|
|
|
# We then serialize the current state of the database into a string
|
|
|
|
--- a/django/db/backends/base/creation.py
|
|
+++ b/django/db/backends/base/creation.py
|
|
@@ -1,4 +1,5 @@
|
|
import os
|
|
import sys
|
|
from io import StringIO
|
|
|
|
+from django.apps import apps
|
|
+from django.conf import settings
|
|
from django.core import serializers
|
|
from django.db import router
|
|
|
|
@@ -58,6 +60,7 @@ class BaseDatabaseCreation:
|
|
test_database_name = self._get_test_db_name()
|
|
|
|
if verbosity >= 1:
|
|
action = 'Creating'
|
|
if keepdb:
|
|
action = "Using existing"
|
|
@@ -68,6 +71,21 @@ class BaseDatabaseCreation:
|
|
interactive=False,
|
|
database=self.connection.alias,
|
|
run_syncdb=True,
|
|
)
|
|
+ else:
|
|
+ old_migration_modules = settings.MIGRATION_MODULES
|
|
+ try:
|
|
+ settings.MIGRATION_MODULES = {
|
|
+ app.label: None
|
|
+ for app in apps.get_app_configs()
|
|
+ }
|
|
+ call_command(
|
|
+ 'migrate',
|
|
+ verbosity=max(verbosity - 1, 0),
|
|
+ interactive=False,
|
|
+ database=self.connection.alias,
|
|
+ run_syncdb=True,
|
|
+ )
|
|
+ finally:
|
|
+ settings.MIGRATION_MODULES = old_migration_modules
|
|
|
|
# We then serialize the current state of the database into a string
|
|
|
|
Let me produce the clean patch:
|
|
|
|
--- a/django/db/backends/base/creation.py
|
|
+++ b/django/db/backends/base/creation.py
|
|
@@ -1,6 +1,7 @@
|
|
import os
|
|
import sys
|
|
from io import StringIO
|
|
|
|
+from django.apps import apps
|
|
+from django.conf import settings
|
|
from django.core import serializers
|
|
from django.db import router
|
|
|
|
@@ -68,6 +70,21 @@ class BaseDatabaseCreation:
|
|
database=self.connection.alias,
|
|
run_syncdb=True,
|
|
)
|
|
+ else:
|
|
+ old_migration_modules = settings.MIGRATION_MODULES
|
|
+ try:
|
|
+ settings.MIGRATION_MODULES = {
|
|
+ app.label: None
|
|
+ for app in apps.get_app_configs()
|
|
+ }
|
|
+ call_command(
|
|
+ 'migrate',
|
|
+ verbosity=max(verbosity - 1, 0),
|
|
+ interactive=False,
|
|
+ database=self.connection.alias,
|
|
+ run_syncdb=True,
|
|
+ )
|
|
+ finally:
|
|
+ settings.MIGRATION_MODULES = old_migration_modules
|
|
|
|
# We then serialize the current state of the database into a string
|