django-pk-to-uuid icon indicating copy to clipboard operation
django-pk-to-uuid copied to clipboard

Writing custom Django migrations to convert data type of Primary Key, also updating Foreign Keys.

Django PK to UUID

Django migrations to convert integer primary key to UUID, also updating Foreign Keys. This has been tested on PostgreSQL database.

We have created two initial models in our Django app named app as follows:

class Office(models.Model):
    office_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=30)
    description = models.TextField()


class Employee(models.Model):
    employee_id = models.AutoField(primary_key=True)
    office = models.ForeignKey(Office, on_delete=models.CASCADE)
    name = models.CharField(max_length=30)
    description = models.TextField()

The model Employee has a foreign key office (stored as office_id in the db). The field office_id in Office is currently of type Integer. We wish to now convert this to UUID. We make the following changes to the Office model:

class Office(models.Model):
    office_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=30)
    description = models.TextField()

The model Employee stays the same. When Django autogenerated migrations are run, they throw an error, as it only tries to cast the int values to UUID. Making this change requires us to write our own migrations. You will find this in the django_pk_to_uuid.py file in the repository. Here, I'll describe the steps followed:

  1. In the Office table, add a new field for UUID (office_uuid). Since this is a new field, only pass null=True in the parameters.
  2. We now define a RunPython function, which inputs values into the newly created UUID field.
  3. Now, we can alter the office_uuid field with the parameters default=uuid.uuid4, editable=False, serialize=False

We have successfully created a new office_uuid field, now comes the task of adding it to Employee table:

  1. In the Employee table, create a office_uuid field with null=True
  2. Define a RunPython function, to query with office_id in the Office table, and add the corresponding office_uuid
  3. Remove the field office_id from the Employee table.
  4. Rename the office_uuid field to office_id in the Employee table.

Now that these changes have been done, we go back to the main table, i.e. Office again:

  1. In the Office table, remove the office_id field.
  2. Rename the office_uuid field to office_id in Office.
  3. Alter the new office_id by setting primary_key=True in the parameters.

Now that we have the updated office_id field in both the tables, Office and Employee, only one step remains:

  1. In the Employee table, alter the field office_id and set it as Foreign Key to the Office table.

With this, we're done. Please find the code for the steps in the django_pk_to_uuid.py file.