Opened 90 minutes ago

Last modified 25 minutes ago

#37006 new Bug

Attempting to recreate the PK in a model with no other fields generates a migration that crashes on SQLite

Reported by: Carol Naranjo Owned by:
Component: Migrations Version: 6.0
Severity: Normal Keywords: sqlite, migrations
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When a model contains no fields other than the primary key, and the PK is recreated (e.g., renaming and switching from an AutoField to a UUIDField), Django generates a migration with two operations: RemoveField followed by AddField.

In SQLite, applying this migration fails because SQLite cannot create a table with no columns. It only affects SQLite because in other databases the table can be altered by droping the column, whereas SQLite requires that a new table is created and then the data is copied.

Steps to reproduce:

  1. Starting with a model with only the primary key:
    class Place(models.Model):
        pass # PK is created by default as AutoField with column name "id"
    
  1. Modify the primary key:
    class Place(models.Model):
        uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    
  1. Run makemigrations. Which generates following migration:
class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='place',
            name='id',
        ),
        migrations.AddField(
            model_name='place',
            name='uid',
            field=models.AutoField(primary_key=True, serialize=False),
        ),
    ]
  1. Apply the migration using SQLite.

Observed behavior:

During the RemoveField operation, the generated migration tries to create a table with zero non-PK columns, resulting in:

CREATE TABLE "new__myapp_place" (); (params None)
    sqlite3.OperationalError: near ")": syntax error

Expected behavior:

SQLite migration should not crash. Either prevent a migration that would create a table with zero columns or handle it gracefully.

On a side note: This is an edge case—tables without additional fields are rare—but it still causes an unexpected crash.

Change History (2)

comment:1 by Jacob Walls, 63 minutes ago

Component: Database layer (models, ORM)Migrations
Triage Stage: UnreviewedAccepted

Thanks, reproduced at f6167b8bc881babd19b67c004e8f37954afc192e. Looks like another circumstance that manifests the failure described in #24424.

comment:2 by Simon Charette, 25 minutes ago

Related tickets are #22997 and #29790.

The way SQLite requires the table to be rebuilt on field removal and alterations would likely force us to add a _django_empty_col column to support this workflow.

There might be a way to approach this at the auto-detector level by turning a removal and addition of a Field(primary_key=True) with a different name as a [AlterField, RenameField] instead of a [RemoveField, AddField]. Since a model/table can only have one primary key at a time that seems like a better way to approach this problem as it would then allow us to focus our efforts on getting AlterField(from_pk, to_pk) to work in most cases which is what #29790 is about.

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