Opened 4 months ago

Closed 4 months ago

#36401 closed New feature (wontfix)

Adding CompositePrimaryKey to existing table leads to drop existing PK with not composite PK creation

Reported by: Pavel Tyslacki Owned by:
Component: Migrations Version: 5.2
Severity: Normal Keywords:
Cc: Pavel Tyslacki Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Pavel Tyslacki)

When I define new table with CompositePrimaryKey:

class Test1(models.Model):
    pk = models.CompositePrimaryKey("product_id", "order_id")
    product_id = models.BigIntegerField()
    order_id = models.BigIntegerField()
    quantity = models.IntegerField()

if creates table with

        migrations.CreateModel(
            name='Test1',
            fields=[
                ('pk', models.CompositePrimaryKey('product_id', 'order_id', blank=True, editable=False, primary_key=True, serialize=False)),
                ('product_id', models.BigIntegerField()),
                ('order_id', models.BigIntegerField()),
                ('quantity', models.IntegerField()),
            ],
        ),

and final SQL:

CREATE TABLE "blog_test1" ("product_id" bigint NOT NULL, "order_id" bigint NOT NULL, "quantity" integer NOT NULL, PRIMARY KEY ("product_id", "order_id"));

But if I has existing table:

class Test2(models.Model):
    #pk = models.CompositePrimaryKey("product_id", "order_id")
    product_id = models.BigIntegerField()
    order_id = models.BigIntegerField()
    quantity = models.IntegerField()
         migrations.CreateModel(
            name='Test2',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('product_id', models.BigIntegerField()),
                ('order_id', models.BigIntegerField()),
                ('quantity', models.IntegerField()),
            ],
        ),

and try to add CompositePrimaryKey, in this case next migration created:

        migrations.RemoveField(
            model_name='test2',
            name='id',
        ),
        migrations.AddField(
            model_name='test2',
            name='pk',
            field=models.CompositePrimaryKey('product_id', 'order_id', blank=True, editable=False, primary_key=True, serialize=False),
        ),

and migration SQL will look next:

--
-- Remove field id from test2
--
ALTER TABLE "blog_test2" DROP COLUMN "id" CASCADE;
--
-- Add field pk to test2
--
-- (no-op)

in this case old PK will be dropped, but new CompositePrimaryKey will not created.

Expected no matter is model created in one or two steps, final db table will have same PK constraints, eg. CompositePrimaryKey will be created if we add it to existing table.

Issue presented at least in postgres and sqlite.

Change History (2)

comment:1 by Pavel Tyslacki, 4 months ago

Description: modified (diff)
Summary: Adding CompositePrimaryKey to exiting table leads to drop existing PK with not composit PK creationAdding CompositePrimaryKey to existing table leads to drop existing PK with not composite PK creation

comment:2 by Jacob Walls, 4 months ago

Resolution: wontfix
Status: newclosed
Type: BugNew feature

Hi, thanks for the report. This is documented as not supported:

Django doesn’t support migrating to, or from, a composite primary key after the table is created. It also doesn’t support adding or removing fields from the composite primary key.
If you would like to migrate an existing table from a single primary key to a composite primary key, follow your database backend’s instructions to do so.
Once the composite primary key is in place, add the CompositePrimaryKey field to your model. This allows Django to recognize and handle the composite primary key appropriately.

Adding support for this would be a new feature, so setting a "wontfix" status on this tracker with the reason that new features are currently tracked elsewhere.

Note: See TracTickets for help on using tickets.
Back to Top