In my sqlalchemy model i use sqlalchemy_utils' choicetype:
id = db.Column(db.Integer, primary_key=True)
code = db.Column(db.Integer, nullable=True)
level = db.Column(mytypes.types.ChoiceType(LEVEL))
I did everything as described here http://alembic.readthedocs.org/en/latest/autogenerate.html#autogen-module-prefix. In my model i imported choicetype from my module mytypes.types:
from sqlalchemy_utils.types.choice import ChoiceType
, in alembic/env.py i added context
context.configure(
connection=connection,
target_metadata=target_metadata,
user_module_prefix="mytypes.types."
# ...
)
, and in the script.py.mako
import mytypes.types
.The problem is when i am making revision of my model, i getting something
like this
from alembic import op
import sqlalchemy as sa
import mytypes.types
def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.add_column('logging', sa.Column('level', mytypes.types.ChoiceType(length=255), nullable=True))
### end Alembic commands ###
Why alembic didn't pass "LEVEL" argument to choicetype and why it passed length=255 instead?
I fixed it by manually change this
mytypes.types.ChoiceType(length=255)
to
mytypes.types.ChoiceType(MyEnum)
and import it.
I've come up with a more automated solution for this problem. In my env.py, in the function run_migrations_online(), I've added a custom render that handles the sqlalchemy_utils types. I've only tested with ChoiceType and UUIDType, but they work for me.
So in env.py and the custom render function:
def render_item(type_, obj, autogen_context):
"""Apply custom rendering for selected items."""
if type_ == "type" and obj.__class__.__module__.startswith("sqlalchemy_utils."):
autogen_context.imports.add(f"import {obj.__class__.__module__}")
if hasattr(obj, "choices"):
return f"{obj.__class__.__module__}.{obj.__class__.__name__}(choices={obj.choices})"
else:
return f"{obj.__class__.__module__}.{obj.__class__.__name__}()"
# default rendering for other objects
return False
Then I modified the existing context configure to use it:
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
render_item=render_item,
process_revision_directives=process_revision_directives,
**current_app.extensions["migrate"].configure_args,
)
This means when I run manage.py db migrate
with a new sqlalchemy_utils it correctly imports the module and adds the type to the migrarions. I've add special handling for the choices attributes of the ChoiceType. It's possible this will need to be extended for more types/attributes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With