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 defaultpk
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
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.
- Django – how to get user logged in (get_queryset in ListView)
- Running django in virtualenv – ImportError: No module named django.core.management?
- Django (admin.e104) must inherit from 'InlineModelAdmin'
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.
- Using a custom form in a modelformset factory?
- Django: String representation of models
- Creating users in django (NOT NULL constraint failed: auth_user.last_login)