from django.db import models class Author(models.Model): name = models.CharField(max_length=255) class Book(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey(Author, on_delete=models.CASCADE)
It is tricky because Book
references an Author
via id
, which is
currently an
integer. When it changes to a uuid though, then Book
will have an integer reference
to a uuid field, and the database will raise errors. We work around this by downgrading
the foreign key to a regular IntegerField
and slowly massaging it to use the new uuid
primary key of Book
.
Steps
-
Add
uuid
field toAuthor
while preserving theid
field as an integer -
Populate
uuid
in the migration per Migrations that Add Unique Fields -
Alter
Book
'sauthor
foreign key reference toAuthor
to be an integer -
Make
uuid
theAuthor
's primary key -
Rename
Book
'sauthor
toauthor_old
-
Add a new
author
foreign key field toBook
-
Create new empty migration
python manage.py makemigrations --empty library
-
Add a
RunPython
step to empty migration that populatesauthor
fromauthor_old
for each book row -
Remove
Author
'sid
-
Rename
Author
'suuid
toid
-
Drop
author_old
-
Make the
Book
'sauthor
null again -
Squash the new migrations. This ensures that the database is not in a weird state if only half of the migrations get applied.
-
python manage.py squashmigrations library 0002 0012
-
Follow the steps stated in the command output and the migration file to copy the custom
populate_*
functions into the squashed migration -
Delete old migrations that the squashed migration replaces
-
Rename the squashed migration
-
Bonus points for using ulid
instead of the standard uuid.uuid4
!
See the git commit history in my example repository. This is a good way to see the result of each step.
← Back to blog