Search code examples
djangoprimary-keydjango-migrations

Add integer primary_key in production


We have a running instance of a Django Backend. On a few model we used an CharField as an Primary Key because it was the best solution for the old requirements. Now we need to add a basic int id like

id = models.AutoField(primary_key=True)

and let the old charfield remain as primary_key=False.

I removed the primary_key=True Flag from the old primary key attribute and triggered ./manage.py makemigrations. If I don't declare any primary key Django is generating its normal id like mentioned above. But after trigger, Djang asks for default values for old entries of this model like:

It is impossible to add a non-nullable field 'id' to anrede without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit and manually define a default value in models.py.

Becaus it's a unique field, I can't use any static content. So how can I still make migrations without deleting old migrations?


Solution

  • The usual way to implement this is:

    1. Add a new (non-unique, nullable) id field to the model and generate the migration scripts.
    2. Write a data migration that populates the id column incrementally for existing records.
    3. Add primary_key=True to the new id field (and remove null=True) and generate the migration scrips.

    Now you will have 3 migrations that should do what you want when executed in that order.

    Note that you should also reset your auto-increment counter using sqlsequencereset management command. You should also consider foreign keys (if any) that refer to this model.