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
uuidfield toAuthorwhile preserving theidfield as an integer -
Populate
uuidin the migration per Migrations that Add Unique Fields -
Alter
Book'sauthorforeign key reference toAuthorto be an integer -
Make
uuidtheAuthor's primary key -
Rename
Book'sauthortoauthor_old -
Add a new
authorforeign key field toBook -
Create new empty migration
python manage.py makemigrations --empty library
-
Add a
RunPythonstep to empty migration that populatesauthorfromauthor_oldfor each book row -
Remove
Author'sid -
Rename
Author'suuidtoid -
Drop
author_old -
Make the
Book'sauthornull 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