开发者

How to automatically reflect table relationships in SQLAlchemy or SqlSoup ORM?

How do I tell SQLAlchemy to automatically reflect basic Foreign Key references as references to other ORM objects and not integer fields?

In both SQLAlchemy and it's SqlSoup, table columns are reflected automatically开发者_如何学运维 and relations can be defined manually:

class User(Base):
    __table__ = metadata.tables['users']
    loan = relation(Loans)

...

You can define relationships on SqlSoup classes:
>>> db.users.relate('loans', db.loans)


Try this magic ) Works for simple FK relations, and without db schemes

from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import mapper, relation

engine = create_engine("sqlite://", echo=True)

engine.execute('''
    create table foo (
        id integer not null primary key,
        x integer
    )''')

engine.execute('''
    create table bar (
        id integer not null primary key,
        foo_id integer,
        FOREIGN KEY(foo_id) REFERENCES foo(id)
    )''')

metadata = MetaData()
metadata.reflect(bind=engine)


MAPPERS = {
}

repr_name = lambda t: '%s%s' % (t[0].upper(), t[1:])

for table in metadata.tables:

    cls = None
    # 1. create class object
    cls_name = repr_name(str(table))
    exec("""class %s(object): pass""" % cls_name)
    exec("""cls = %s""" % cls_name)

    # 2. collect relations by FK
    properties = {}
    for c in metadata.tables[table].columns:
        for fk in c.foreign_keys:
            name = str(fk.column).split('.')[0]
            properties.update({
                name: relation(lambda: MAPPERS[repr_name(name)]),
            })

    # 3. map table to class object 
    mapper(cls, metadata.tables[table], properties=properties)


    MAPPERS.update({cls_name: cls})

if __name__ == '__main__':
    from sqlalchemy.orm import sessionmaker

    print 'Mappers: '
    for m in MAPPERS.values():
        print m

    session = sessionmaker(bind=engine)()

    foo = Foo()
    foo.x = 1
    session.add(foo)

    session.commit()

    print session.query(Foo).all()

    bar = Bar()
    bar.foo = foo
    session.add(bar)
    session.commit()

    print session.query(Bar).all()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜