From ec73fd67466e0e4841d9ecd0f217c02ce842d860 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Mon, 28 Apr 2025 23:35:04 -0400 Subject: [PATCH] [5.2.x] Fixed #36358 -- Corrected introspection of composite primary keys on SQLite. Previously, any first field of a composite primary key with type `INTEGER` was incorrectly introspected as an `AutoField` due to SQLite treating `INTEGER PRIMARY KEY` as an alias for the `ROWID`. This change ensures that integer fields in composite PKs are not mistaken for auto-incrementing fields. Thanks Jacob Walls and Sarah Boyce for the reviews. Backport of 07100db6f46255ec6ef70b860495f977473684d6 from main. --- django/db/backends/sqlite3/introspection.py | 13 +++++++++++-- docs/releases/5.2.1.txt | 4 ++++ tests/inspectdb/tests.py | 11 ++--------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py index a21bc22413..780a5e90d4 100644 --- a/django/db/backends/sqlite3/introspection.py +++ b/django/db/backends/sqlite3/introspection.py @@ -115,7 +115,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): ).fetchone() if has_json_constraint: json_columns.add(column) - return [ + table_description = [ FieldInfo( name, data_type, @@ -126,7 +126,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): not notnull, default, collations.get(name), - pk == 1, + bool(pk), name in json_columns, ) for cid, name, data_type, notnull, default, pk, hidden in table_info @@ -137,6 +137,15 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): 3, # Stored generated column. ] ] + # If the primary key is composed of multiple columns they should not + # be individually marked as pk. + primary_key = [ + index for index, field_info in enumerate(table_description) if field_info.pk + ] + if len(primary_key) > 1: + for index in primary_key: + table_description[index] = table_description[index]._replace(pk=False) + return table_description def get_sequences(self, cursor, table_name, table_fields=()): pk_col = self.get_primary_key_column(cursor, table_name) diff --git a/docs/releases/5.2.1.txt b/docs/releases/5.2.1.txt index 19d14bbddf..8ec4d58a92 100644 --- a/docs/releases/5.2.1.txt +++ b/docs/releases/5.2.1.txt @@ -55,3 +55,7 @@ Bugfixes * Fixed a regression in Django 5.2 that caused a crash when using ``update()`` on a ``QuerySet`` filtered against a related model and including references to annotations through ``values()`` (:ticket:`36360`). + +* Fixed a bug in composite primary key introspection that caused + ``IntegerField`` to be wrongly identified as ``AutoField`` on SQLite + (:ticket:`36358`). diff --git a/tests/inspectdb/tests.py b/tests/inspectdb/tests.py index c5f4ba4c6c..8c544c58c3 100644 --- a/tests/inspectdb/tests.py +++ b/tests/inspectdb/tests.py @@ -628,10 +628,7 @@ class InspectDBTransactionalTests(TransactionTestCase): def test_composite_primary_key(self): out = StringIO() - if connection.vendor == "sqlite": - field_type = connection.features.introspected_field_types["AutoField"] - else: - field_type = connection.features.introspected_field_types["IntegerField"] + field_type = connection.features.introspected_field_types["IntegerField"] call_command("inspectdb", "inspectdb_compositeprimarykeymodel", stdout=out) output = out.getvalue() self.assertIn( @@ -639,8 +636,4 @@ class InspectDBTransactionalTests(TransactionTestCase): output, ) self.assertIn(f"column_1 = models.{field_type}()", output) - self.assertIn( - "column_2 = models.%s()" - % connection.features.introspected_field_types["IntegerField"], - output, - ) + self.assertIn(f"column_2 = models.{field_type}()", output)