relationship(). Thanks to Kent Bower
for tests. [ticket:2374]
+ - [feature] New declarative reflection example
+ added, illustrates how best to mix table reflection
+ with declarative as well as uses some new features
+ from [ticket:2356].
+
- sql
- [feature] New reflection feature "autoload_replace";
when set to False on Table, the Table can be autoloaded
--- /dev/null
+"""
+Illustrates how to mix table reflection with Declarative, such that
+the reflection process itself can take place **after** all classes
+are defined. Declarative classes can also override column
+definitions loaded from the database.
+
+At the core of this example is the ability to change how Declarative
+assigns mappings to classes. The ``__mapper_cls__`` special attribute
+is overridden to provide a function that gathers mapping requirements
+as they are established, without actually creating the mapping.
+Then, a second class-level method ``prepare()`` is used to iterate
+through all mapping configurations collected, reflect the tables
+named within and generate the actual mappers.
+
+The example is new in 0.7.5 and makes usage of the new
+``autoload_replace`` flag on :class:`.Table` to allow declared
+classes to override reflected columns.
+
+Usage example::
+
+ Base= declarative_base(cls=DeclarativeReflectedBase)
+
+ class Foo(Base):
+ __tablename__ = 'foo'
+ bars = relationship("Bar")
+
+ class Bar(Base):
+ __tablename__ = 'bar'
+ foo_id = Column(Integer, ForeignKey('foo.id'))
+
+ Base.prepare(e)
+
+ s = Session(e)
+
+ s.add_all([
+ Foo(bars=[Bar(data='b1'), Bar(data='b2')], data='f1'),
+ Foo(bars=[Bar(data='b3'), Bar(data='b4')], data='f2')
+ ])
+ s.commit()
+
+
+"""
--- /dev/null
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from sqlalchemy.ext.declarative import declarative_base, declared_attr
+
+class DeclarativeReflectedBase(object):
+ _mapper_args = []
+
+ @classmethod
+ def __mapper_cls__(cls, *args, **kw):
+ """Declarative will use this function in lieu of
+ calling mapper() directly.
+
+ Collect each series of arguments and invoke
+ them when prepare() is called.
+ """
+
+ cls._mapper_args.append((args, kw))
+
+ @classmethod
+ def prepare(cls, engine):
+ """Reflect all the tables and map !"""
+ for args, kw in cls._mapper_args:
+ klass = args[0]
+ klass.__table__ = table = Table(
+ klass.__tablename__,
+ cls.metadata,
+ extend_existing=True,
+ autoload_replace=False,
+ autoload=True,
+ autoload_with=engine,
+ )
+ klass.__mapper__ = mapper(klass, table, **kw)
+
+
+if __name__ == '__main__':
+ Base= declarative_base(cls=DeclarativeReflectedBase)
+
+ class Foo(Base):
+ __tablename__ = 'foo'
+ bars = relationship("Bar")
+
+ class Bar(Base):
+ __tablename__ = 'bar'
+ foo_id = Column(Integer, ForeignKey('foo.id'))
+
+ e = create_engine('sqlite://', echo=True)
+ e.execute("""
+ create table foo(
+ id integer primary key,
+ data varchar(30)
+ )
+ """)
+
+ e.execute("""
+ create table bar(
+ id integer primary key,
+ data varchar(30),
+ foo_id integer
+ )
+ """)
+
+ Base.prepare(e)
+
+ s = Session(e)
+
+ s.add_all([
+ Foo(bars=[Bar(data='b1'), Bar(data='b2')], data='f1'),
+ Foo(bars=[Bar(data='b3'), Bar(data='b4')], data='f2')
+ ])
+ s.commit()
+ for f in s.query(Foo):
+ print f.data, ",".join([b.data for b in f.bars])
\ No newline at end of file