summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2026-03-08 10:44:56 +0100
committerGitHub <noreply@github.com>2026-03-08 10:44:56 +0100
commita5c49174b96302f39682cce48f82da67b3b08351 (patch)
tree00ccff1c2fdecdd0f536c04a9a89eb5fbe94e5ee
parent0ae0029c2f4d82af937e9632cd5bf13e81e91f98 (diff)
Fixed #12529 -- Fixed migrate --run-syncdb crash for existing model with truncated db_table names.
-rw-r--r--django/core/management/commands/migrate.py4
-rw-r--r--tests/migrations/migrations_test_apps/unmigrated_app_syncdb/models.py5
-rw-r--r--tests/migrations/test_commands.py53
3 files changed, 58 insertions, 4 deletions
diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py
index 268f669ba2..62ad29e43d 100644
--- a/django/core/management/commands/migrate.py
+++ b/django/core/management/commands/migrate.py
@@ -6,6 +6,7 @@ from django.apps import apps
from django.core.management.base import BaseCommand, CommandError, no_translations
from django.core.management.sql import emit_post_migrate_signal, emit_pre_migrate_signal
from django.db import DEFAULT_DB_ALIAS, connections, router
+from django.db.backends.utils import truncate_name
from django.db.migrations.autodetector import MigrationAutodetector
from django.db.migrations.executor import MigrationExecutor
from django.db.migrations.loader import AmbiguityError
@@ -447,8 +448,9 @@ class Command(BaseCommand):
def model_installed(model):
opts = model._meta
converter = connection.introspection.identifier_converter
+ max_name_length = connection.ops.max_name_length()
return not (
- (converter(opts.db_table) in tables)
+ (converter(truncate_name(opts.db_table, max_name_length)) in tables)
or (
opts.auto_created
and converter(opts.auto_created._meta.db_table) in tables
diff --git a/tests/migrations/migrations_test_apps/unmigrated_app_syncdb/models.py b/tests/migrations/migrations_test_apps/unmigrated_app_syncdb/models.py
index 9f3179cd0d..c539b20d11 100644
--- a/tests/migrations/migrations_test_apps/unmigrated_app_syncdb/models.py
+++ b/tests/migrations/migrations_test_apps/unmigrated_app_syncdb/models.py
@@ -7,3 +7,8 @@ class Classroom(models.Model):
class Lesson(models.Model):
classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE)
+
+
+class VeryLongNameModel(models.Model):
+ class Meta:
+ db_table = "long_db_table_that_should_be_truncated_before_checking"
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index 6a0d9bd6d2..e9929c1eaf 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -25,6 +25,7 @@ from django.db import (
connections,
models,
)
+from django.db.backends.base.introspection import BaseDatabaseIntrospection
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.backends.utils import truncate_name
from django.db.migrations.autodetector import MigrationAutodetector
@@ -1222,10 +1223,10 @@ class MigrateTests(MigrationTestBase):
create_table_count = len(
[call for call in execute.mock_calls if "CREATE TABLE" in str(call)]
)
- self.assertEqual(create_table_count, 2)
+ self.assertEqual(create_table_count, 3)
# There's at least one deferred SQL for creating the foreign key
# index.
- self.assertGreater(len(execute.mock_calls), 2)
+ self.assertGreater(len(execute.mock_calls), 3)
stdout = stdout.getvalue()
self.assertIn("Synchronize unmigrated apps: unmigrated_app_syncdb", stdout)
self.assertIn("Creating tables...", stdout)
@@ -1259,8 +1260,54 @@ class MigrateTests(MigrationTestBase):
create_table_count = len(
[call for call in execute.mock_calls if "CREATE TABLE" in str(call)]
)
- self.assertEqual(create_table_count, 2)
+ self.assertEqual(create_table_count, 3)
+ self.assertGreater(len(execute.mock_calls), 3)
+ self.assertIn(
+ "Synchronize unmigrated app: unmigrated_app_syncdb", stdout.getvalue()
+ )
+
+ @override_settings(
+ INSTALLED_APPS=[
+ "migrations.migrations_test_apps.unmigrated_app_syncdb",
+ "migrations.migrations_test_apps.unmigrated_app_simple",
+ ]
+ )
+ def test_migrate_syncdb_installed_truncated_db_model(self):
+ """
+ Running migrate --run-syncdb doesn't try to create models with long
+ truncated name if already exist.
+ """
+ with connection.cursor() as cursor:
+ mock_existing_tables = connection.introspection.table_names(cursor)
+ # Add truncated name for the VeryLongNameModel to the list of
+ # existing table names.
+ table_name = truncate_name(
+ "long_db_table_that_should_be_truncated_before_checking",
+ connection.ops.max_name_length(),
+ )
+ mock_existing_tables.append(table_name)
+ stdout = io.StringIO()
+ with (
+ mock.patch.object(BaseDatabaseSchemaEditor, "execute") as execute,
+ mock.patch.object(
+ BaseDatabaseIntrospection,
+ "table_names",
+ return_value=mock_existing_tables,
+ ),
+ ):
+ call_command(
+ "migrate", "unmigrated_app_syncdb", run_syncdb=True, stdout=stdout
+ )
+ create_table_calls = [
+ str(call).upper()
+ for call in execute.mock_calls
+ if "CREATE TABLE" in str(call)
+ ]
+ self.assertEqual(len(create_table_calls), 2)
self.assertGreater(len(execute.mock_calls), 2)
+ self.assertFalse(
+ any([table_name.upper() in call for call in create_table_calls])
+ )
self.assertIn(
"Synchronize unmigrated app: unmigrated_app_syncdb", stdout.getvalue()
)