Postgres uuid field in an earlier migration

Hi guys, I’m trying to deploy using docker to a postgres database but I’m getting the psycopg2.errors.CannotCoerce: cannot cast type bigint to uuid error.
Problem is the affected migration is 18 migrations ago so the “delete it, delete the field and then create a new field” solution I’ve seen elsewhere is a bit more complicated. Anyone got any suggestions how I can fix it?

Do you have a bit more context info? What are your actual changes, that create the bigint to uuid hassle? Did you change the pk type of a very old django project (pre 3.2) by any chance? Normally the fact, that the change is like 18 migrations in the past, should not impact you - django would just spool through them (unless there are already issues in former migrations you missed).

(Sidenote: There was a bug in the related field resolving in pre 3.2 versions, where uuid pks could get misinterpreted as ints.)

Hi jerch,
This is a project running on 4.2.1, I’m
The reason it hadn’t been caught earlier is that I have only just started Dockerizing the app to prep to move it to a production environment. Before this it had been running with a SQLite db for dev purposes.

The issue is that at migration 4 I changed the type of the ID field from the default int to UUID. When I try and build the Docker container I get the error I described at migration 4 since apparently Postgres can’t convert from int to uuid and thus won’t go any further in the migration chain.

This is the contents of the relevant migration:

# Generated by Django 3.2.8 on 2021-10-21 14:56

from django.db import migrations, models
import uuid


class Migration(migrations.Migration):

    dependencies = [
        ('car', '0003_car_colour'),
    ]

    operations = [
        migrations.AlterField(
            model_name='car',
            name='id',
            field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False),
        ),
    ]

And here is the traceback for the error I’m getting (the latest migration in this app is 022)

Traceback (most recent call last):
2023-06-08T09:01:24.860520100Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 87, in _execute
2023-06-08T09:01:24.860945300Z     return self.cursor.execute(sql)
2023-06-08T09:01:24.860994900Z psycopg2.errors.CannotCoerce: cannot cast type bigint to uuid
2023-06-08T09:01:24.861004500Z LINE 1: ...TABLE "car_car" ALTER COLUMN "id" TYPE uuid USING "id"::uuid
2023-06-08T09:01:24.861009900Z                                                                  ^
2023-06-08T09:01:24.861014500Z 
2023-06-08T09:01:24.861071100Z 
2023-06-08T09:01:24.861114900Z The above exception was the direct cause of the following exception:
2023-06-08T09:01:24.861127100Z 
2023-06-08T09:01:24.861133400Z Traceback (most recent call last):
2023-06-08T09:01:24.861138500Z   File "/home/<myproject>/<myproject>/manage.py", line 22, in <module>
2023-06-08T09:01:24.861225500Z     main()
2023-06-08T09:01:24.861245500Z   File "/home/<myproject>/<myproject>/manage.py", line 18, in main
2023-06-08T09:01:24.861416600Z     execute_from_command_line(sys.argv)
2023-06-08T09:01:24.861465300Z   File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
2023-06-08T09:01:24.861670400Z     utility.execute()
2023-06-08T09:01:24.861725000Z   File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 436, in execute
2023-06-08T09:01:24.862037700Z     self.fetch_command(subcommand).run_from_argv(self.argv)
2023-06-08T09:01:24.862090900Z   File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 412, in run_from_argv
2023-06-08T09:01:24.862317000Z     self.execute(*args, **cmd_options)
2023-06-08T09:01:24.862368700Z   File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 458, in execute
2023-06-08T09:01:24.862647300Z     output = self.handle(*args, **options)
2023-06-08T09:01:24.862711100Z   File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 106, in wrapper
2023-06-08T09:01:24.862723600Z     res = handle_func(*args, **kwargs)
2023-06-08T09:01:24.862759900Z   File "/usr/local/lib/python3.9/site-packages/django/core/management/commands/migrate.py", line 356, in handle
2023-06-08T09:01:24.863065300Z     post_migrate_state = executor.migrate(
2023-06-08T09:01:24.863122000Z   File "/usr/local/lib/python3.9/site-packages/django/db/migrations/executor.py", line 135, in migrate
2023-06-08T09:01:24.863534700Z     state = self._migrate_all_forwards(
2023-06-08T09:01:24.863595000Z   File "/usr/local/lib/python3.9/site-packages/django/db/migrations/executor.py", line 167, in _migrate_all_forwards
2023-06-08T09:01:24.863689800Z     state = self.apply_migration(
2023-06-08T09:01:24.863747400Z   File "/usr/local/lib/python3.9/site-packages/django/db/migrations/executor.py", line 252, in apply_migration
2023-06-08T09:01:24.863985000Z     state = migration.apply(state, schema_editor)
2023-06-08T09:01:24.864040700Z   File "/usr/local/lib/python3.9/site-packages/django/db/migrations/migration.py", line 132, in apply
2023-06-08T09:01:24.864497700Z     operation.database_forwards(
2023-06-08T09:01:24.864552800Z   File "/usr/local/lib/python3.9/site-packages/django/db/migrations/operations/fields.py", line 235, in database_forwards
2023-06-08T09:01:24.865029900Z     schema_editor.alter_field(from_model, from_field, to_field)
2023-06-08T09:01:24.865076600Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/schema.py", line 830, in alter_field
2023-06-08T09:01:24.865964300Z     self._alter_field(
2023-06-08T09:01:24.866016000Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/postgresql/schema.py", line 287, in _alter_field
2023-06-08T09:01:24.866474400Z     super()._alter_field(
2023-06-08T09:01:24.866517500Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/schema.py", line 1055, in _alter_field
2023-06-08T09:01:24.866831700Z     self.execute(
2023-06-08T09:01:24.866877800Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/postgresql/schema.py", line 48, in execute
2023-06-08T09:01:24.866893300Z     return super().execute(sql, None)
2023-06-08T09:01:24.866903600Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/schema.py", line 201, in execute
2023-06-08T09:01:24.867102700Z     cursor.execute(sql, params)
2023-06-08T09:01:24.867155900Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 67, in execute
2023-06-08T09:01:24.867211700Z     return self._execute_with_wrappers(
2023-06-08T09:01:24.867269600Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
2023-06-08T09:01:24.867441700Z     return executor(sql, params, many, context)
2023-06-08T09:01:24.867503500Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 89, in _execute
2023-06-08T09:01:24.867544300Z     return self.cursor.execute(sql, params)
2023-06-08T09:01:24.867560000Z   File "/usr/local/lib/python3.9/site-packages/django/db/utils.py", line 91, in __exit__
2023-06-08T09:01:24.868032100Z     raise dj_exc_value.with_traceback(traceback) from exc_value
2023-06-08T09:01:24.868079400Z   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 87, in _execute
2023-06-08T09:01:24.868115800Z     return self.cursor.execute(sql)
2023-06-08T09:01:24.868128400Z django.db.utils.ProgrammingError: cannot cast type bigint to uuid
2023-06-08T09:01:24.868134600Z LINE 1: ...TABLE "car_car" ALTER COLUMN "id" TYPE uuid USING "id"::uuid
2023-06-08T09:01:24.868140400Z                                                                  ^
2023-06-08T09:01:24.868145500Z 
2023-06-08T09:01:24.956208500Z   Applying car.0004_alter_car_id...Collecting static files...

Hope this makes sense.

This sounds like your production target has no real-world data yet? If thats the case, you could either try sqashing the migrations on that model into just one initial (more friendly to all dev instances, but caution - needs to be applied on all dev instances before you can remove the old migration cascade), or go with a faked initial (more disruptive, would not be my first choice).

If there is no real-world data yet at all, well - delete all migrations, remove db files on dev instances, and startover from scratch (makemigrations → migrate, creates initial migrations with uuid field in the first place).

That’s correct, no real world data yet and I’m the only dev so the complete deletion and remake the migrations is probably the best option for simplicity (annoying but what can you do).

Just to check, the fact that the primary key is a UUID won’t inherently cause issues with Postgres? Also the new migration cascade will need to work with other models that may have a dependency on it, should I also redo those models or will it compensate?

Thanks

Nope, thats just fine for postgres.

Yes - well a proper squash can deal with that, also a wipe + fresh initial would also handle it correctly.

Since you have no real data yet and you are the only dev, imho starting over from scratch for all your models is prolly the simplest way. Most annoying part for me would be the fact, that the VCS (idk if you use git etc) has still broken code in older commits for postgres, but again - not much to be done other than just fixing it at some point.

Sounds like a problem for another day.

Many thanks for your help jerch.