[Solved]-How to make UUID field default when there's already ID field

31👍

here are the list of actions that you need to do

1 – add the new uuid field to model (I name this model Base) then generate migration files

uuid = models.UUIDField(default=uuid4, blank=True, null=True)

  • note that uuid is not primarykey yet
  • note that blank = null =True

2- in this step you should populate uuid field with valid data. you should write a data migration file for Base model. please check docs for more info

your forwards method should be something like this:

for item in Base.objects.all():
    item.uuid = uuid4()
    item.save()

3- change uuid field to this and generate migrations

uuid = models.UUIDField(default=uuid4, unique=True)

  • note that uuid is not primarykey yet, but it’s unique now

4 – for other models which are pointing to Base model you should add a new foreignkey pointing to uuid field

assumig your default relation to Base model is something like this

base = models.ForeignKey(
    Base, on_delete=models.PROTECT, related_name='base'
)

you should add a temprory field like this

base_uuid = models.ForeignKey(
    Base,
    on_delete=models.PROTECT,
    related_name='base_uuid',
    to_field='uuid',
    blank=True,
    null=True,
)
  • note that I have explicitly defined to_field which tell django this foreign key is not pointing to default pk field
  • you should keep old foreign key field
  • also set blank = null = True
  • for all foreignkeys/manytomanyfield pointing to Base you should add this temp field

5- in this step you should create a data migration file,

in this data migration file you need to fill all base_uuid fields with valid data (based on old base field) your migration code can be something like this

for item in RelatedModel.objects.all():
    item.base_uuid_id = item.base.uuid
  • after this step all base_uuid fields in all models should contain a valid data

6- in all related models drop related field (keep the new base_uuid field but discard old related field) and generate a migration file

7- delete the db_constraint on all FK fields – this is needed, because django will connect through the unique constraint from base_uuid which will be dropped if we change uuid to pk.

base_uuid = models.ForeignKey(
    Base,
    on_delete=models.PROTECT,
    related_name='base_uuid',
    to_field='uuid',
    blank=True,
    null=True,
    db_constraint=False
)

8- in Base model change uuid field and generate a migration file

uuid = models.UUIDField(default=uuid4, primary_key=True)

  • uuid is now a primary key!

9- in all related models (models which you have added base_uuid fields) update the field

  • rename field name (remove _uuid from column name) (make this a individual Migration!)
  • change relate_name field name (remove _uuid from related name)
  • remove blank = null = true if necessary
  • remove to_field='uuid' argument (you don’t need that any more)

Very Important Note: run these code with test data and create a full backup from your database before running this code on your actual data

👤aliva

0👍

I don’t have enough rep to add a comment to the answer by @aliva. I believe there is an error with step 5.

for item in RelatedModel.objects.all():
item.base_uuid_id = item.base

drop the .uuid from item.base

I was getting an error Cannot assign "UUID(‘…’)" must be a "Base" instance.

0👍

This is a relatively simple solution, but use this only if you can afford to delete the whole data in the DB currently (you may have just started the project).

Reset the migrations

  • Delete all the migrations in the migrations folder except the init.py file.
  • Run python manage.py makemigrations
  • Run python manage.py migrate

This will create entirely new migrations for your application, and you won’t face any type issues in this case as the type of the uuid field gets set in the initial migration field itself.

Leave a comment