Lingfeng Xiong
Lingfeng Xiong

Reputation: 1171

SQLAlchemy - Any way to reflect a database schema with user input connection string?

Here's a pretty interesting question... I'm writing a program to manipulate several remote databases with same schema via SQLAlchemy. The connection string is not static -- it is stored in a local SQLite database. I need to create a session at runtime, and use that session to reflect the database schema. All databases have same schema. I have already know the table names. Anyway to implement this?

def connect(connstr):
    engine = create_engine(connstr)
    metadata = MetaData(bind=engine)
    session = create_session(bind=engine)
    return session

class User(Base):
    # How it's possible to create a dummy model class without predefined metadata?
    __table__ = Table('users', metadata, autoload=True)

EDIT: finally I solved this problem by myself:

Base = declarative_base()

def connect(connstr):
    engine = create_engine(connstr)
    metadata = MetaData(bind=engine)
    session = create_session(bind=engine)
    return metadata, session

def get_model(metadata, modelname, tablename):
    cls = type(modelname, (Base,), dict(
        __table__ = Table(tablename, metadata, autoload = True)
    ))
    return cls

However, @Gary van der Merwe's answer is pretty cool!

Upvotes: 2

Views: 1552

Answers (1)

Gary van der Merwe
Gary van der Merwe

Reputation: 9533

You have to manually map the orm classes to the reflected tables.

Assuming a database with the following structure:

CREATE TABLE "group" (
        id INTEGER NOT NULL, 
        name VARCHAR(50), 
        PRIMARY KEY (id)
)

CREATE TABLE user (
        id INTEGER NOT NULL, 
        name VARCHAR(50), 
        password VARCHAR(12), 
        group_id INTEGER, 
        PRIMARY KEY (id), 
        FOREIGN KEY(group_id) REFERENCES "group" (id)
)

you can do:

#!/usr/bin/env python

from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import mapper, Session, relationship


class Group(object):
    def __init__(self, name):
        self.name = name

class User(object):
    def __init__(self, name, password, group):
        self.name = name
        self.password = password
        self.group = group

    group = relationship(Group)

def connect(url):
    engine = create_engine(url, echo=True)
    metadata = MetaData(engine, reflect=True)

    # Do this for each table
    mapper(User, metadata.tables['group'])
    mapper(Group, metadata.tables['user'])


    session = Session(bind=engine)
    return session


session = connect('sqlite:///test.db')
finance_group = Group('finance')
session.add(finance_group)
session.add(User('joe', 'password', finance_group))
session.commit()
print(session.query(User).all())

Upvotes: 3

Related Questions