使用 SQLAlchemy 反映来自 postgres DB 的每个模式
reflecting every schema from postgres DB using SQLAlchemy
我有一个现有数据库,它有两个模式,名为 schools
和 students
,包含在 declarative_base
的实例中,并通过两个不同的 类 继承自那个例子
class DirectorioEstablecimiento(Base):
__table_args__ = {'schema': 'schools'}
__tablename__ = 'addresses'
# some Columns are defined here
和
class Matricula(Base):
__table_args__ = {'schema': 'students'}
__tablename__ = 'enrollments'
# some Columns are defined here
我可以使用 Base
实例作为 Base.metadata.create_all(bind=engine)
在我在 postgres 中的测试数据库中重新创建它。如果我查询 pg_namespace
,我可以确认这是没有问题的
In [111]: engine.execute("SELECT * FROM pg_namespace").fetchall()
2017-12-13 18:04:01,006 INFO sqlalchemy.engine.base.Engine SELECT * FROM pg_namespace
2017-12-13 18:04:01,006 INFO sqlalchemy.engine.base.Engine {}
Out[111]:
[('pg_toast', 10, None),
('pg_temp_1', 10, None),
('pg_toast_temp_1', 10, None),
('pg_catalog', 10, '{postgres=UC/postgres,=U/postgres}'),
('public', 10, '{postgres=UC/postgres,=UC/postgres}'),
('information_schema', 10, '{postgres=UC/postgres,=U/postgres}'),
('schools', 16386, None),
('students', 16386, None)]
以及来自 psql CLI
user# select * from pg_tables;
schemaname | tablename | tableowner | tablespace | hasindexes | hasrules | hastriggers | rowsecurity
--------------------+------------------------------+------------+------------+------------+----------+-------------+-------------
schools | addresses | diego | | t | f | f | f
students | enrollments | diego | | t | f | f | f
pg_catalog | pg_statistic | postgres | | t | f | f | f
pg_catalog | pg_type | postgres | | t | f | f | f
pg_catalog | pg_authid | postgres | pg_global | t | f | f | f
pg_catalog | pg_user_mapping | postgres | | t | f | f | f
-- other tables were omitted
但是,如果我想在 declarative_base
的某些其他实例中反映该数据库,则不会反映任何内容。
类似
In [87]: Base.metadata.tables.keys()
Out[87]: dict_keys(['schools.addresses', 'students.enrollments'])
In [88]: new_base = declarative_base()
In [89]: new_base.metadata.reflect(bind=engine)
In [90]: new_base.metadata.tables.keys()
Out[90]: dict_keys([])
我知道 reflect
接受一个 schema
作为参数,但我想在反思期间一次获得所有这些参数。出于某种原因,我一次可以做到这一点。
有办法吗?
当您调用 metadata.reflect()
时,它只会反映默认架构(您有权访问 search_path
中的第一个架构)。因此,如果您的 search_path 是 public,students,school
,它只会反映模式 public
中的 table。如果您没有模式 public 的权限,public
模式将被跳过并且默认仅反映 students
.
默认架构由 SELECT current_schema();
检索
为了反映其他模式
您需要为每个模式调用 metadata.reflect()
。
metadata.reflect(schema='public') # will reflect even if you do not have permissions on the tables in schema `public`, as long as you have access to pg_* system tables
metadata.reflect(schema='students')
metadata.reflect(schema='schools')
Note: When you reflect with an explicit schema
Reflected tables in metadata.tables
will have the keys with the tables fully qualified schema name as in schema1.mytable
, schema2.mytable
Any conflicting table names will be replaced with the later one. If you have any tables with the same name, you should implement your the function classname_for_table
to prefix the names with the schema name.
table 名称前缀示例
def classname_for_table(base, tablename, table):
schema_name = table.schema
fqname = '{}.{}'.format(schema_name, tablename)
return fqname
Base.prepare(classname_for_table=classname_for_table)
**作为奖励,这里有一个小片段,它将在每个模式的动态子模块中公开所有 table,以便您可以访问它 **
创建一个文件,即。 db.py 并放置以下内容
from types import ModuleType
def register_classes(base, module_dict):
for name, table in base.classes.items():
schema_name, table_name = name.split('.')
class_name = table_name.title().replace('_', '')
if schema_name not in module_dict:
module = module_dict[schema_name] = ModuleType(schema_name)
else:
module = module_dict[schema_name]
setattr(module, class_name, table)
使用自动映射库和您要注册模式的模块的 __dict__
调用此函数。
register_classes(base, globals())
或
import db
db.register_classes(base, db.__dict__)
然后你会得到
import db
db.students.MyTable
db.schools.MyTable
我有一个现有数据库,它有两个模式,名为 schools
和 students
,包含在 declarative_base
的实例中,并通过两个不同的 类 继承自那个例子
class DirectorioEstablecimiento(Base):
__table_args__ = {'schema': 'schools'}
__tablename__ = 'addresses'
# some Columns are defined here
和
class Matricula(Base):
__table_args__ = {'schema': 'students'}
__tablename__ = 'enrollments'
# some Columns are defined here
我可以使用 Base
实例作为 Base.metadata.create_all(bind=engine)
在我在 postgres 中的测试数据库中重新创建它。如果我查询 pg_namespace
In [111]: engine.execute("SELECT * FROM pg_namespace").fetchall()
2017-12-13 18:04:01,006 INFO sqlalchemy.engine.base.Engine SELECT * FROM pg_namespace
2017-12-13 18:04:01,006 INFO sqlalchemy.engine.base.Engine {}
Out[111]:
[('pg_toast', 10, None),
('pg_temp_1', 10, None),
('pg_toast_temp_1', 10, None),
('pg_catalog', 10, '{postgres=UC/postgres,=U/postgres}'),
('public', 10, '{postgres=UC/postgres,=UC/postgres}'),
('information_schema', 10, '{postgres=UC/postgres,=U/postgres}'),
('schools', 16386, None),
('students', 16386, None)]
以及来自 psql CLI
user# select * from pg_tables;
schemaname | tablename | tableowner | tablespace | hasindexes | hasrules | hastriggers | rowsecurity
--------------------+------------------------------+------------+------------+------------+----------+-------------+-------------
schools | addresses | diego | | t | f | f | f
students | enrollments | diego | | t | f | f | f
pg_catalog | pg_statistic | postgres | | t | f | f | f
pg_catalog | pg_type | postgres | | t | f | f | f
pg_catalog | pg_authid | postgres | pg_global | t | f | f | f
pg_catalog | pg_user_mapping | postgres | | t | f | f | f
-- other tables were omitted
但是,如果我想在 declarative_base
的某些其他实例中反映该数据库,则不会反映任何内容。
类似
In [87]: Base.metadata.tables.keys()
Out[87]: dict_keys(['schools.addresses', 'students.enrollments'])
In [88]: new_base = declarative_base()
In [89]: new_base.metadata.reflect(bind=engine)
In [90]: new_base.metadata.tables.keys()
Out[90]: dict_keys([])
我知道 reflect
接受一个 schema
作为参数,但我想在反思期间一次获得所有这些参数。出于某种原因,我一次可以做到这一点。
有办法吗?
当您调用 metadata.reflect()
时,它只会反映默认架构(您有权访问 search_path
中的第一个架构)。因此,如果您的 search_path 是 public,students,school
,它只会反映模式 public
中的 table。如果您没有模式 public 的权限,public
模式将被跳过并且默认仅反映 students
.
默认架构由 SELECT current_schema();
为了反映其他模式
您需要为每个模式调用 metadata.reflect()
。
metadata.reflect(schema='public') # will reflect even if you do not have permissions on the tables in schema `public`, as long as you have access to pg_* system tables
metadata.reflect(schema='students')
metadata.reflect(schema='schools')
Note: When you reflect with an explicit schema
Reflected tables in metadata.tables
will have the keys with the tables fully qualified schema name as inschema1.mytable
,schema2.mytable
Any conflicting table names will be replaced with the later one. If you have any tables with the same name, you should implement your the function classname_for_table
to prefix the names with the schema name.
table 名称前缀示例
def classname_for_table(base, tablename, table):
schema_name = table.schema
fqname = '{}.{}'.format(schema_name, tablename)
return fqname
Base.prepare(classname_for_table=classname_for_table)
**作为奖励,这里有一个小片段,它将在每个模式的动态子模块中公开所有 table,以便您可以访问它 **
创建一个文件,即。 db.py 并放置以下内容
from types import ModuleType
def register_classes(base, module_dict):
for name, table in base.classes.items():
schema_name, table_name = name.split('.')
class_name = table_name.title().replace('_', '')
if schema_name not in module_dict:
module = module_dict[schema_name] = ModuleType(schema_name)
else:
module = module_dict[schema_name]
setattr(module, class_name, table)
使用自动映射库和您要注册模式的模块的 __dict__
调用此函数。
register_classes(base, globals())
或
import db
db.register_classes(base, db.__dict__)
然后你会得到
import db
db.students.MyTable
db.schools.MyTable