Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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),
),
]
@PFischbeck
Copy link

PFischbeck commented Aug 28, 2017

Removing the unique=True in lines 39 and 53 made the migration reversible for me. For some reason, this allows the primary key constraint on the UUIDField to be dropped.

@BossGrand
Copy link

BossGrand commented Aug 28, 2017

how do you deal with foreign keys?

@dchaplinsky
Copy link

dchaplinsky commented Mar 4, 2018

Thank you bro!

@manuganji
Copy link

manuganji commented May 10, 2018

@PFischbeck: a primary key has to be unique. Don't know how you plan to use it as a primary key without uniqueness constraint.

@marodrig
Copy link

marodrig commented Oct 17, 2018

Removing the unique=True in lines 39 and 53 made the migration reversible for me. For some reason, this allows the primary key constraint on the UUIDField to be dropped.

Hi, I came across this because I am migrating models. First, thank you for the gist. Second, from the documentation, primary_key=True implies null=False and unique=True, so I am guessing that was creating some conflict with your implicit 'unique=True'.

@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.

@thlnndrs
Copy link

thlnndrs 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