6

I'm trying to create a user model that uses UUID as primary key:

from src.db import db # SQLAlchemy instance

import sqlalchemy_utils

import uuid


class User(db.Model):
    __tablename__ = 'user'

    id = db.Column(sqlalchemy_utils.UUIDType(binary=True), primary_key=True, nullable=False)

But when I generate the migrations I receive:

File "/home/pc/Downloads/project/auth/venv/lib/python3.6/site-packages/alembic/runtime/environment.py", line 836, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/home/pc/Downloads/project/auth/venv/lib/python3.6/site-packages/alembic/runtime/migration.py", line 330, in run_migrations
step.migration_fn(**kw)
  File "/home/pc/Downloads/project/auth/migrations/versions/efae4166f832_.py", line 22, in upgrade
    sa.Column('id', sqlalchemy_utils.types.uuid.UUIDType(length=16), nullable=False),
NameError: name 'sqlalchemy_utils' is not defined`

I had try to explicity inform the module I'm using like this and use a 'internal' implementation that SQLAlchemy

Obs: If I manualy import the sqlalchemy_utils in the /migrations/version/efae4166f832_.py and remove the length that is generated automaticaly sa.Column('id', sqlalchemy_utils.types.uuid.UUIDType(length=16), nullable=False) it works fine

I generate the migrations using a generate.py script:

from src import create_app

from src.db import db

from flask_migrate import Migrate

# Models

from src.user.models.user import User

app = create_app()

migrate = Migrate(app, db)`

enter image description here

Obs: MySQL engine

I expect that when I generate migration it generate a user model that uses UUID implemented from SQLAlchemy Utils as primary key

5 Answers5

13

You have just to add:

import sqlalchemy_utils

to your script.py.mako inside migrations folder

Marco Caggiano
  • 308
  • 2
  • 8
  • 1
    I did something very similar - add that line to the top of my migrations/versions/9d34543545.py file – Rimu Atkinson Oct 29 '19 at 03:12
  • If I add only the import to the script.py.mako file is not enough to solve the problem. – Iván May 04 '21 at 17:51
  • 2
    Adding the import line to script.py.mako will automatically add it to any new migration scripts that you generate. If you added the import line to script.py.mako after some previous migration scripts were already generated, you will have to manually add the import line to the previously generated scripts as well. – djsosofresh Sep 20 '22 at 21:00
2

Thanks, Marco, but I have already fixed it. I have put the import import sqlalchemy_utils inside env.py and script.py.mako, I have also put the following function:

def render_item(type_, obj, autogen_context):
    """Apply custom rendering for selected items"""

    if type_ == "type" and isinstance(obj, sqlalchemy_utils.types.uuid.UUIDType):
        # Add import for this type
        autogen_context.imports.add("import sqlalchemy_utils")

        autogen_context.imports.add("import uuid")

        return "sqlalchemy_utils.types.uuid.UUIDType(), default=uuid.uuid4"

    # Default rendering for other objects
    return False

Inside the env.py, and at the same file I have set render_item=render_item in the function run_migrations_online:

context.configure(
    ...,
    render_item=render_item,
    ...
)

I researched to do this automatically, but I couldn't find nothing that could help me.

The order of the operations matter:

  1. export FLASK_APP=manage.py

  2. flask db init

  3. Do the tutorial above

  4. flask db migrate

  5. flask db upgrade

2

Background

It would be ideal if you didn't have to go and manually edit each migration file with an import sqlalchemy_utils statement.

Looking at the Alembic documentation, script.py.mako is "a Mako template file which is used to generate new migration scripts." Therefore, you'll need to re-generate your migration files, with Mako already importing sqlalchemy_utils as part of the migration file generation.

Fix

If possible, remove your old migrations (they're probably broken anyway), and add the import sqlalchemy_utils like so to your script.py.mako file:

from alembic import op
import sqlalchemy as sa
import sqlalchemy_utils #<-- line you add
${imports if imports else ""}

then just rerun your alembic migrations:

alembic revision --autogenerate -m "create initial tables"

when you go to look at your migration file you should see sqlalchemy_utils already imported via the mako script.

hope that helps.

AndrewO
  • 1,105
  • 4
  • 16
  • 33
  • Indeed I had to delete the previous migration file 4564fde54544df.py something and add ```import sqlalchemy_utils``` to ```script.py.mako``` to run – William Le Sep 08 '22 at 07:47
1

Adding import sqlalchemy_utils in the script.py.mako file will automatically import this line on all the migration files that are generated and resolve the issue.

from alembic import op
import sqlalchemy as sa
import sqlalchemy_utils
${imports if imports else ""}
Rupesh Goud
  • 131
  • 1
  • 9
0

Add the import sqlalchemy_utils line to the newly-created migrations/versions/{hash}_my_comment.py file. However, this will only fix the problem for that specific step of the migration. If you expect that you'll be making lots of changes to columns which reference sqlalchemy_utils, you should probably do something more robust like Walter's suggestion. Even then, though, it looks like you may need to add code to properly deal with each column type you end up using.

NB: Despite seeing the suggestion in multiple places of just adding the import line to the script.py.mako file, that did not work for me.

Nick K9
  • 3,885
  • 1
  • 29
  • 62