]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- [feature] New declarative reflection example
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 28 Jan 2012 22:31:39 +0000 (17:31 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 28 Jan 2012 22:31:39 +0000 (17:31 -0500)
added, illustrates how best to mix table reflection
with declarative as well as uses some new features
from [ticket:2356].

CHANGES
examples/declarative_reflection/__init__.py [new file with mode: 0644]
examples/declarative_reflection/declarative_reflection.py [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index ed7a9320640a05306d9e43b3be0ebb65f1f417d7..df1cc83fdc878e2ea84a49beb69b0b00446fb63d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -79,6 +79,11 @@ CHANGES
     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
diff --git a/examples/declarative_reflection/__init__.py b/examples/declarative_reflection/__init__.py
new file mode 100644 (file)
index 0000000..3c6be72
--- /dev/null
@@ -0,0 +1,42 @@
+"""
+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()
+
+"""
diff --git a/examples/declarative_reflection/declarative_reflection.py b/examples/declarative_reflection/declarative_reflection.py
new file mode 100644 (file)
index 0000000..88f191b
--- /dev/null
@@ -0,0 +1,72 @@
+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