我有一个现有的数据库,它有两个模式,名为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
作为参数,但我希望在反思期间立即获得所有这些参数。出于某种原因,我可以一次实现这一目标。
有办法做到这一点吗?
答案 0 :(得分:2)
调用metadata.reflect()
时,它将仅反映默认模式(search_path
中第一个具有权限的模式)。因此,如果您的search_path为public,students,school
,它将仅反映模式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')
注意:当您使用显式架构进行反映时
在 metadata.tables
中反映的表将具有与表中的表名完全合格的键,如schema1.mytable
,schema2.mytable
任何有冲突的表名都将替换为后一个。如果有任何具有相同名称的表,则应实现函数 classname_for_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)
**此外,这是一个小片段,它将按模式显示动态子模块中的所有表,以便您可以访问它**
创建一个文件,即。 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