I need to add a new UUID column to an existing SQLAlchemy / MySQL table where.
For doing so I added in my database model:
class MyTable(db.Model):
uid = db.Column(db.BINARY(16), nullable=False, unique=True, default=uuid.uuid4)
Doing so generates the following alembic upgrade code which of course does not work as the default value if the new column is null
:
op.add_column('my_table', sa.Column('uid', sa.BINARY(length=16), nullable=True))
op.create_unique_constraint(None, 'my_table', ['uid'])
I tried to extend the db.Column(db.BINARY(16), nullable=False, unique=True, default=uuid.uuid4)
definition with an appropriate server_default=...
parameter but wasn’t able to find a parameter that generates for each row a new random UUID.
How to add a new column and generate for all existing rows a new random and unique UUID value?
A solution that uses sa.String
instead of sa.BINARY
would also be acceptable.
2
Answers
In the end I manually created the necessary UPDATE statements in the alembic update file so existing rows are assigned a unique UID.
For new entries
default=uuid.uuid4
in the SQLAlchemy column definition is sufficient.Note that the MySQL
UUID()
function generates timestamp based UUID values for the existing records, and new records created via Python/SQLAlchemy useuuid.uuid4
which generates a v4 (random) UUID. So both are UUIDs but you will see which UUIDs were generated byUUID()
as they only differ in the first block when generating them using the UPDATE statement.Using binary column type
Using String/varchar column type
As per mysqlalchemy’s documentation on server_default:
Based on this, your
server_default
definition should look like this:However, if your mysql version is earlier than v8.0.12, then you cannot use the server side default like this, you need to use either the default with setting uuid from python or you need a trigger as specified in the following SO question: MySQL set default id UUID