Getting SQLAlchemy to issue CREATE SCHEMA on create_all

Question:

I have a SqlAlchemy model with a schema argument like so:

Base = declarative_base()

class Road(Base):
  __tablename__ = "roads"
  __table_args__ = {'schema': 'my_schema'}
  id = Column(Integer, primary_key=True)

When I use Base.metadata.create_all(engine) it correctly issues a CREATE TABLE with the schema name on the front like so CREATE TABLE my_schema.roads ( but Postgresql rightly complains that the schema doesn’t exist.

Am I missing a step to get SqlAlchemy to issue the CREATE SCHEMA my_schema or do I have to call this manually?

Asked By: Rory Hart

||

Answers:

I have done it manually on my db init script like so:

from sqlalchemy.schema import CreateSchema
engine.execute(CreateSchema('my_schema'))

But this seems less magical than I was expecting.

Answered By: Rory Hart

I ran into the same issue and believe the “cleanest” way of issuing the DDL is something like this:

from sqlalchemy import event
from sqlalchemy.schema import CreateSchema

event.listen(Base.metadata, 'before_create', CreateSchema('my_schema'))

This will ensure that before anything contained in the metadata of your base is created, you have the schema for it. This does, however, not check if the schema already exists.

You can do CreateSchema('my_schema').execute_if(callback_=check_schema) if you can be bothered to write the check_schema callback (“Controlling DDL Sequences” on should_create in docs). Or, as an easy way out, just use DDL("CREATE SCHEMA IF NOT EXISTS my_schema") instead (for Postgres):

from sqlalchemy import DDL

event.listen(Base.metadata, 'before_create', DDL("CREATE SCHEMA IF NOT EXISTS my_schema"))
Answered By: vicvicvic

I wrote a function that creates the declared schemas based on the accepted answer. It uses the schema value from the __table_args__ dict from each mapped class.

from sqlalchemy import event, DDL


# Import or write your mapped classes and configuration here

def init_db():
    for mapper in Base.registry.mappers:
        cls = mapper.class_
        if issubclass(cls, Base):
            table_args = getattr(cls, '__table_args__', None)
            if table_args:
                schema = table_args.get('schema')
                if schema:
                    stmt = f"CREATE SCHEMA IF NOT EXISTS {schema}"
                    event.listen(Base.metadata, 'before_create', DDL(stmt))
    Base.metadata.create_all(bind=engine)
Answered By: Maicon Mauricio
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.