Skip to content

Instantly share code, notes, and snippets.

@smcoll
Last active January 24, 2024 15:55
Show Gist options
  • Star 42 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save smcoll/8bb867dc631433c01fd0 to your computer and use it in GitHub Desktop.
Save smcoll/8bb867dc631433c01fd0 to your computer and use it in GitHub Desktop.
Django migration converting integer pk table to UUID pk table
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import uuid
from django.db import migrations, models
def fill_mymodel_uuid(apps, schema_editor):
db_alias = schema_editor.connection.alias
MyModel = apps.get_model('myapp', 'MyModel')
for obj in MyModel.objects.using(db_alias).all():
obj.uuid = uuid.uuid4()
obj.save()
class Migration(migrations.Migration):
""" Change model with integer pk to UUID pk. This migration presumes there
are no db constraints (foreign keys) to this table.
"""
dependencies = [
# ...
]
operations = [
migrations.AddField(
model_name='mymodel',
name='uuid',
field=models.UUIDField(null=True),
),
migrations.RunPython(fill_mymodel_uuid, migrations.RunPython.noop),
migrations.AlterField(
model_name='mymodel',
name='uuid',
field=models.UUIDField(default=uuid.uuid4, serialize=False, editable=False, unique=True),
),
migrations.RemoveField('MyModel', 'id'),
migrations.RenameField(
model_name='mymodel',
old_name='uuid',
new_name='id'
),
migrations.AlterField(
model_name='mymodel',
name='id',
field=models.UUIDField(primary_key=True, default=uuid.uuid4, serialize=False, editable=False),
),
]
@gabn88
Copy link

gabn88 commented Aug 27, 2019

Thanks for this!

@smcoll
Copy link
Author

smcoll commented Aug 27, 2019

Thanks @PFischbeck and @marodrig - not sure how i missed those comments long ago. Gist is updated.

@zlove
Copy link

zlove commented Sep 8, 2019

Thanks for this @smcoll. Why is the migrations.RunPython.noop necessary?

@smcoll
Copy link
Author

smcoll commented Sep 9, 2019

@gabn88
Copy link

gabn88 commented Oct 26, 2019

how do you deal with foreign keys?

I have the following issue: 'Cannot add foreign key constraint'. It happens on the migrations.RemoveField('MyModel', 'id') step. Don't know how to fix it, Django 1.11.

@smcoll
Copy link
Author

smcoll commented Nov 3, 2019

@gabn88 that's trickier. Off the top of my head, i think you have to do something like this, with each step as its own migration file:

  1. add the new UUID column to this model, fill it with unique values, make it NOTNULL/unique (operations 1-3 in this gist)
  2. (for each referencing model) add a new UUID column which stores a UUID (nullable at first)
  3. fill that column with the UUID value corresponding to the integer ID value for the referenced object
  4. update the new UUID field on the referencing model so it's a foreign key type (using to_field), and make it notnull (adding the constraint)
  5. drop the original foreign key column on the referencing model
  6. drop the original id field of this model (operation 4 in this gist)

Notice that i left out the last two operations... if you want an id column and corresponding foo_id columns on the related tables (rather than uuid and foo_uuid columns), then i think you have to drop the foreign key constraints altogether, do the column renaming, and then add the constraints back afterward.

Please someone correct me if i'm wrong there.

@sharshub
Copy link

sharshub commented Apr 28, 2021

@smcoll @gabn88 I have uploaded code, which ensures that the foreign key relations are maintained. Please check it out here: https://github.com/sharshub/django-pk-to-uuid.

@smcoll, thanks for this, it helped with my migrations. I used this to build upon and implement my code.

@thielena
Copy link

thielena commented May 1, 2022

@sharshub Thanks für this really good help!

Have you or (anyone else here) done it for many2many relations as well? I have no idea how to change the id's in the intermediate tables.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment