Abduhamidov Jordan
Abduhamidov Jordan

Reputation: 43

Alembic migrations in ormar not working (FastAPI)

I want to migrate through Alembic, but something doesn't work. I don't understand what exactly I'm doing wrong.

My alembic .env

from logging.config import fileConfig

from sqlalchemy import create_engine
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from db import ORMAR_DATABASE_URL
from alembic import context
import sys, os

sys.path.append(os.getcwd())
config = context.config

fileConfig(config.config_file_name)

from db import Base
target_metadata = Base.metadata
URL = "postgresql://admin:admin@localhost/fa_naesmi"



def run_migrations_offline():


context.configure(
    url=URL,
    target_metadata=target_metadata,
    literal_binds=True,
    dialect_opts={"paramstyle": "named"},
    user_module_prefix='sa.'
)

with context.begin_transaction():
    context.run_migrations()


def run_migrations_online():
connectable = create_engine(URL)

with connectable.connect() as connection:
    context.configure(
        connection=connection,
        target_metadata=target_metadata,
        user_module_prefix='sa.'
    )

    with context.begin_transaction():
        context.run_migrations()


if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()

my db.py file:

import sqlalchemy
import databases
from sqlalchemy.ext.declarative import declarative_base
ORMAR_DATABASE_URL = "postgresql://admin:admin@localhost/fa_naesmi"

Base = declarative_base()
metadata = sqlalchemy.MetaData()
database = databases.Database(ORMAR_DATABASE_URL)
engine = sqlalchemy.create_engine(ORMAR_DATABASE_URL)

and my models.py:

import datetime
import ormar
from typing import Optional
from db import database, metadata, Base


class MainMeta(Base, ormar.ModelMeta):
    metadata = metadata
    database = database


class Category(Base, ormar.Model):
    class Meta(MainMeta):
        pass

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)

after using alembic revision -m "first", it doesn't migrate my models.

revision = '9176fb20d67a'
down_revision = '9159cff21eb5'
branch_labels = None
depends_on = None

def upgrade():
    pass


def downgrade():
    pass

I already wrote in console alembic revision --autogenerate -m "razraz" and it creates alembic database tables, but migrations still not working.

Upvotes: 3

Views: 2246

Answers (1)

collerek
collerek

Reputation: 261

The error is caused by usage of declarative_base() from sqlalchemy.

Sqlalchemy consists of two main parts:

  • ORM - which is a object relational mapping part with Models, relations, queries etc.
  • core - which is much more 'raw' and basic and in general it's related to table and columns creation, as well as queries generation (joins, where clause etc.)

In ormar only the latter is used and you cannot apply any concept from the ORM part. In fact ormar is kind of (simplified by async and pydantic based) equivalent of the ORM part.

That means that you cannot inherit from Base <- that's the orm part I mentioned.

So your sample should look something like following snippets:

alembic .env

from logging.config import fileConfig
from sqlalchemy import create_engine

from db import ORMAR_DATABASE_URL
from models import metadata # adjust path if needed
from alembic import context
import sys, os

sys.path.append(os.getcwd())
config = context.config

fileConfig(config.config_file_name)

# note how it's 'raw' metadata not the one attached to Base as there is no Base
target_metadata = metadata
URL = ORMAR_DATABASE_URL


def run_migrations_offline():


context.configure(
    url=URL,
    target_metadata=target_metadata,
    literal_binds=True,
    dialect_opts={"paramstyle": "named"},
    user_module_prefix='sa.'
)

with context.begin_transaction():
    context.run_migrations()


def run_migrations_online():
connectable = create_engine(URL)

with connectable.connect() as connection:
    context.configure(
        connection=connection,
        target_metadata=target_metadata,
        user_module_prefix='sa.'
    )

    with context.begin_transaction():
        context.run_migrations()


if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()

db.py file:

import sqlalchemy
import databases
ORMAR_DATABASE_URL = "postgresql://admin:admin@localhost/fa_naesmi"

# note lack of declarative_base
metadata = sqlalchemy.MetaData()
database = databases.Database(ORMAR_DATABASE_URL)
engine = sqlalchemy.create_engine(ORMAR_DATABASE_URL)

models.py:

import datetime
import ormar
from typing import Optional
from db import database, metadata


# you cannot subclass Base class thats ORM part
class MainMeta(ormar.ModelMeta):
    metadata = metadata
    database = database


class Category(ormar.Model):
    class Meta(MainMeta):
        pass

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)

Disclaimer: I'm creator of ormar - if you have more questions or trouble with getting it to work let me know here. If that solves you issue remember to mark answer as accepted.

Thanks!

Upvotes: 7

Related Questions