Recently, I wanted to use PasswordType field from SQLAlchemy Utils.
The previous field was some custom implementation which was working in a similar way as PasswordType from SQLAlchemy, with sha256.
I wanted to change it because I found a bug in our custom implementation and I realized that we can use ready implementation from SQLAlchemy Utils.
I’ve changed
password = Column(Password(256), nullable=False)to
password = Column(PasswordType( schemes=['pbkdf2_sha512']))where Password was based on sqlalchemy.types.String.
I wanted to create a migration.
alembic revision --autogenerate -m 'Use PasswordType from SQLAlchemy utils'In my case it printed something like this:
INFO [alembic.autogenerate.compare] Detected NULL on column 'mymodel.password'INFO [alembic.autogenerate.compare] Detected type change from VARCHAR(length=256) to PasswordType(length=1137) on 'mymodel.password'Autogenerated migration:
"""Use PasswordType from SQLAlchemy utils
Revision ID: a79871436520Revises: 828798e9fb9fCreate Date: 2017-05-27 21:31:04.497795
"""from alembic import opimport sqlalchemy as sa
# revision identifiers, used by Alembic.revision = 'a79871436520'down_revision = '828798e9fb9f'branch_labels = Nonedepends_on = None
def upgrade(): ### commands auto generated by Alembic - please adjust! ### op.alter_column('mymodel', 'password', existing_type=sa.VARCHAR(length=256), type_=sqlalchemy_utils.types.password.PasswordType(length=1137), nullable=True) ### end Alembic commands ###
def downgrade(): ### commands auto generated by Alembic - please adjust! ### op.alter_column('mymodel', 'password', existing_type=sqlalchemy_utils.types.password.PasswordType(length=1137), type_=sa.VARCHAR(length=256), nullable=False) ### end Alembic commands ###When I wanted to use it, I got an exception about missing import.
alembic upgrade headNameError: name 'sqlalchemy_utils' is not definedIt was simple. I just imported sqlalchemy_utils.
I run alembic upgrade head once again.
KeyError: "unknown CryptContext keyword: 'length'"That was also very simple. I’ve just changed length to max_length.
Next issue.
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) column "password" cannot be cast automatically to type byteaHINT: You might need to specify "USING password::bytea". [SQL: 'ALTER TABLE mymodel ALTER COLUMN password TYPE BYTEA ']This error required additional parameter in upgrade method.
postgresql_using='password::bytea'You can read about it in documentation.
postgresql_using – String argument which will indicate a SQL expression to render within the Postgresql-specific USING clause within ALTER COLUMN. This string is taken directly as raw SQL which must explicitly include any necessary quoting or escaping of tokens within the expression.
Final migrations look like this:
"""Use PasswordType from SQLAlchemy utils
Revision ID: a79871436520Revises: 828798e9fb9fCreate Date: 2017-05-27 21:31:04.497795
"""from alembic import opimport sqlalchemy as saimport sqlalchemy_utils
# revision identifiers, used by Alembic.revision = 'a79871436520'down_revision = '828798e9fb9f'branch_labels = Nonedepends_on = None
def upgrade(): op.alter_column( 'mymodel', 'password', existing_type=sa.VARCHAR(length=256), type_=sqlalchemy_utils.types.password.PasswordType( max_length=1137 ), nullable=True, postgresql_using='password::bytea' )
def downgrade(): op.alter_column( 'mymodel', 'password', existing_type=sqlalchemy_utils.types.password.PasswordType( max_length=1137 ), type_=sa.VARCHAR(length=256), nullable=False )Works as expected!
root@51805978fa17:/project# alembic upgrade headINFO [alembic.runtime.migration] Context impl PostgresqlImpl.INFO [alembic.runtime.migration] Will assume transactional DDL.INFO [alembic.runtime.migration] Running upgrade 828798e9fb9f -> a79871436520, Use PasswordType from SQLAlchemy utilsroot@51805978fa17:/project# alembic downgrade -1INFO [alembic.runtime.migration] Context impl PostgresqlImpl.INFO [alembic.runtime.migration] Will assume transactional DDL.INFO [alembic.runtime.migration] Running downgrade a79871436520 -> 828798e9fb9f, Use PasswordType from SQLAlchemy utils