mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-06-07 08:11:50 -04:00
- hypothetical "automap" feature, would extend DeferredReflection to create classes
against the remaining tables within the given metadata.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
# ext/automap.py
|
||||
# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""Define an extension to the :mod:`sqlalchemy.ext.declarative` system
|
||||
which automatically generates mapped classes and attributes from a database
|
||||
schema, typically one which is reflected.
|
||||
|
||||
Features:
|
||||
|
||||
* The given :class:`.MetaData` structure may or may not be reflected.
|
||||
:mod:`.automap` isn't dependent on this.
|
||||
|
||||
* Classes which are known to be present in the :mod:`.automap` structure
|
||||
can be pre-declared with known attributes and settings.
|
||||
|
||||
* The system integrates with the featureset of :mod:`.declarative`, including
|
||||
support of mixins, abstract bases, interoperability with non-automapped
|
||||
classes.
|
||||
|
||||
* The system can build out classes for an entire :class:`.MetaData` structure
|
||||
or for individual :class:`.Table` objects.
|
||||
|
||||
* Relationships between classes are generated based on foreign keys, including
|
||||
that simple many-to-many relationships are also detectable.
|
||||
|
||||
* Hooks are provided for many key points, including:
|
||||
|
||||
* A function which converts the name of table into a mapped class
|
||||
|
||||
* A function which receives a :class:`.Column` object to be mapped and
|
||||
produces the element to be part of the mapping.
|
||||
|
||||
* A function which receives two classes which should generate a
|
||||
:func:`.relationship` and produces the actual :func:`.relationship`.
|
||||
|
||||
* Functions which produce attribute names; given a scalar column,
|
||||
or a class name for a scalar or collection reference, produce an attribute
|
||||
name.
|
||||
|
||||
"""
|
||||
from sqlalchemy.ext.declarative import declarative_base, DeferredReflection
|
||||
from sqlalchemy.ext.declarative.base import _MapperConfig
|
||||
from sqlalchemy.schema import ForeignKeyConstraint
|
||||
from sqlalchemy.orm import relationship, backref
|
||||
from sqlalchemy.util import Properties
|
||||
|
||||
def _classname_for_table(table):
|
||||
return table.name
|
||||
|
||||
def automap_base(metadata, **kw):
|
||||
Base = declarative_base()
|
||||
|
||||
class BaseThing(DeferredReflection, Base):
|
||||
registry = Properties({})
|
||||
|
||||
@classmethod
|
||||
def prepare(cls, engine):
|
||||
cls.metadata.reflect(engine)
|
||||
|
||||
table_to_map_config = dict(
|
||||
(m.local_table, m)
|
||||
for m in _MapperConfig.configs.values()
|
||||
if issubclass(m.cls, cls)
|
||||
)
|
||||
|
||||
for table in cls.metadata.tables.values():
|
||||
if table not in table_to_map_config:
|
||||
mapped_cls = type(
|
||||
_classname_for_table(table),
|
||||
(BaseThing, ),
|
||||
{}
|
||||
)
|
||||
map_config = _MapperConfig.configs[mapped_cls]
|
||||
table_to_map_config[table] = map_config
|
||||
|
||||
for map_config in table_to_map_config.values():
|
||||
_relationships_for_fks(map_config, table_to_map_config)
|
||||
super(BaseThing, cls).prepare(engine)
|
||||
|
||||
@classmethod
|
||||
def _reflect_table(cls, table, engine):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def _sa_decl_prepare(cls, local_table, engine):
|
||||
if engine is not None:
|
||||
super(BaseThing, cls)._sa_decl_prepare(local_table, engine)
|
||||
# expected that the Table is present.
|
||||
_relationships_for_fks(cls, local_table)
|
||||
|
||||
def _relationships_for_fks(map_config, table_to_map_config):
|
||||
local_table = map_config.local_table
|
||||
local_cls = map_config.cls
|
||||
for constraint in local_table.constraints:
|
||||
if isinstance(constraint, ForeignKeyConstraint):
|
||||
fks = constraint.elements
|
||||
referred_table = fks[0].column.table
|
||||
referred_cls = table_to_map_config[referred_table].local_cls
|
||||
|
||||
setattr(
|
||||
local_cls,
|
||||
referred_cls.__name__.lower(),
|
||||
relationship(referred_cls,
|
||||
foreign_keys=[fk.parent for fk in constraint.elements],
|
||||
backref=backref(
|
||||
local_cls.__name__.lower() + "_collection",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user