You need to manually declare new enum values that are added, as it would be difficult to detect (though not impossible, will probably retrofit this answer later). Below is an example migration that reflects PSQL keys back from your Enum
class.
There is also a downgrade functionality, but it will only work if none of Enum
values are being used and is somewhat dangerous.
# revision identifiers, used by Alembic.
from mymodels import MyEnum
revision = ...
down_revision = ....
branch_labels = None
depends_on = None
# By default, SQLAlchemy autogenerates PSQL type
# that is the Enum class name lowercased.
# Because Python enums are created using Python metaclasses,
# you cannot directly read the class name back from the class object (it would return `EnumMeta`).
# You need go through method resolution order table to get the real class instance.
# https://stackoverflow.com/a/54014128/315168
enum_name = MyEnum.mro()[0].__name__.lower()
# PostgreSQL does not have a concept of enum keys and values, only values.
# SQLAlchemy maintains enums in the PostgreSQL by the Python enum key (not value)
# Keys to be added:
enum_keys_to_add = [
MyEnum.new1.name,
MyEnum.new2.name,
]
def upgrade():
for v in enum_keys_to_add:
# Use ALTER TYPE.
# See more information https://www.postgresql.org/docs/9.1/sql-altertype.html
op.execute(f"ALTER TYPE {enum_name} ADD VALUE '{v}'")
# Note that ALTER TYPE is not effective within the same transaction https://medium.com/makimo-tech-blog/upgrading-postgresqls-enum-type-with-sqlalchemy-using-alembic-migration-881af1e30abe
def downgrade():
# https://stackoverflow.com/a/39878233/315168
for v in enum_keys_to_add:
sql = f"""DELETE FROM pg_enum
WHERE enumlabel = '{v}'
AND enumtypid = (
SELECT oid FROM pg_type WHERE typname = '{enum_name}'
)"""
op.execute(sql)
You can also manually inspect the content of your PSQL enum with the following SELECT
:
select enum_range(null::myenum);
enum_range
-----------------------------------------------------------------------------------------------------
{old,new1,new2}