* Your application talks to multiple database engines at different times, which use the *same* set of :class:`Table` objects. It's usually confusing and unnecessary to begin to create "copies" of :class:`Table` objects just so that different engines can be used for different operations. An example is an application that writes data to a "master" database while performing read-only operations from a "read slave". A global :class:`~sqlalchemy.schema.MetaData` object is *not* appropriate for per-request switching like this, although a :class:`~sqlalchemy.schema.ThreadLocalMetaData` object is.
* You are using the ORM :class:`Session` to handle which class/table is bound to which engine, or you are using the :class:`Session` to manage switching between engines. Its a good idea to keep the "binding of tables to engines" in one place - either using :class:`~sqlalchemy.schema.MetaData` only (the :class:`Session` can of course be present, it just has no ``bind`` configured), or using :class:`Session` only (the ``bind`` attribute of :class:`~sqlalchemy.schema.MetaData` is left empty).
+.. _metadata_reflection:
+
Reflecting Tables
-----------------
for table in reversed(meta.sorted_tables):
someengine.execute(table.delete())
+Fine Grained Reflection with Inspector
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A low level interface which provides a backend-agnostic system of loading lists of schema, table, column, and constraint descriptions from a given database is also available. This is known as the "Inspector" and is described in the API documentation at :ref:`inspector_api_toplevel`.
+
Specifying the Schema Name
---------------------------
--- /dev/null
+.. _inspector_api_toplevel:
+
+Schema Introspection
+====================
+
+.. module:: sqlalchemy.engine.reflection
+
+SQLAlchemy provides rich schema introspection capabilities. The most common methods for this include the "autoload" argument of :class:`~sqlalchemy.schema.Table`::
+
+ from sqlalchemy import create_engine, MetaData, Table
+ engine = create_engine('...')
+ meta = MetaData()
+ user_table = Table('user', meta, autoload=True, autoload_with=engine)
+
+As well as the :meth:`~sqlalchemy.schema.MetaData.reflect` method of :class:`~sqlalchemy.schema.MetaData`::
+
+ from sqlalchemy import create_engine, MetaData, Table
+ engine = create_engine('...')
+ meta = MetaData()
+ meta.reflect(engine)
+ user_table = meta.tables['user']
+
+Further examples of reflection using :class:`~sqlalchemy.schema.Table` and :class:`~sqlalchemy.schema.MetaData` can be found at :ref:`metadata_reflection`.
+
+There is also a low-level inspection interface available for more specific operations, known as the :class:`Inspector`::
+
+ from sqlalchemy import create_engine
+ from sqlalchemy.engine import reflection
+ engine = create_engine('...')
+ insp = reflection.Inspector.from_engine(engine)
+ print insp.get_table_names()
+
+.. autoclass:: Inspector
+ :members:
+ :undoc-members:
+ :show-inheritance:
class Inspector(object):
"""Performs database schema inspection.
- The Inspector acts as a proxy to the dialects' reflection methods and
- provides higher level functions for accessing database schema information.
+ The Inspector acts as a proxy to the reflection methods of the
+ :class:`~sqlalchemy.engine.base.Dialect`, providing a
+ consistent interface as well as caching support for previously
+ fetched metadata.
+
+ The preferred method to construct an :class:`Inspector` is via the
+ :meth:`Inspector.from_engine` method. I.e.::
+
+ engine = create_engine('...')
+ insp = Inspector.from_engine(engine)
+
+ Where above, the :class:`~sqlalchemy.engine.base.Dialect` may opt
+ to return an :class:`Inspector` subclass that provides additional
+ methods specific to the dialect's target database.
+
"""
def __init__(self, bind):
- """Initialize the instance.
+ """Initialize a new :class:`Inspector`.
+
+ :param bind: a :class:`~sqlalchemy.engine.base.Connectable`,
+ which is typically an instance of
+ :class:`~sqlalchemy.engine.base.Engine` or
+ :class:`~sqlalchemy.engine.base.Connection`.
+
+ For a dialect-specific instance of :class:`Inspector`, see
+ :meth:`Inspector.from_engine`
- :param bind: a :class:`~sqlalchemy.engine.base.Connectable`
"""
# ensure initialized
self.info_cache = {}
@classmethod
- def from_engine(cls, engine):
- if hasattr(engine.dialect, 'inspector'):
- return engine.dialect.inspector(engine)
- return Inspector(engine)
+ def from_engine(cls, bind):
+ """Construct a new dialect-specific Inspector object from the given engine or connection.
+
+ :param bind: a :class:`~sqlalchemy.engine.base.Connectable`,
+ which is typically an instance of
+ :class:`~sqlalchemy.engine.base.Engine` or
+ :class:`~sqlalchemy.engine.base.Connection`.
+
+ This method differs from direct a direct constructor call of :class:`Inspector`
+ in that the :class:`~sqlalchemy.engine.base.Dialect` is given a chance to provide
+ a dialect-specific :class:`Inspector` instance, which may provide additional
+ methods.
+
+ See the example at :class:`Inspector`.
+
+ """
+ if hasattr(bind.dialect, 'inspector'):
+ return bind.dialect.inspector(engine)
+ return Inspector(bind)
@property
def default_schema_name(self):
+ """Return the default schema name presented by the dialect
+ for the current engine's database user.
+
+ E.g. this is typically ``public`` for Postgresql and ``dbo``
+ for SQL Server.
+
+ """
return self.dialect.default_schema_name
def get_schema_names(self):
return tnames
def get_table_options(self, table_name, schema=None, **kw):
+ """Return a dictionary of options specified when the table of the given name was created.
+
+ This currently includes some options that apply to MySQL tables.
+
+ """
if hasattr(self.dialect, 'get_table_options'):
return self.dialect.get_table_options(self.bind, table_name, schema,
info_cache=self.info_cache,
return indexes
def reflecttable(self, table, include_columns):
-
+ """Given a Table object, load its internal constructs based on introspection.
+
+ This is the underlying method used by most dialects to produce
+ table reflection. Direct usage is like::
+
+ from sqlalchemy import create_engine, MetaData, Table
+ from sqlalchemy.engine import reflection
+
+ engine = create_engine('...')
+ meta = MetaData()
+ user_table = Table('user', meta)
+ insp = Inspector.from_engine(engine)
+ insp.reflecttable(user_table, None)
+
+ :param table: a :class:`~sqlalchemy.schema.Table` instance.
+ :param include_columns: a list of string column names to include
+ in the reflection process. If ``None``, all columns are reflected.
+
+ """
dialect = self.bind.dialect
# MySQL dialect does this. Applicable with other dialects?