我有一对看起来像这样的PostgreSQL表(简化示例):
CREATE TABLE people (
id SERIAL PRIMARY KEY,
created timestamp with time zone DEFAULT now() NOT NULL,
modified timestamp with time zone NULL,
email varchar NOT NULL UNIQUE,
inactive boolean NOT NULL DEFAULT False
);
CREATE TABLE engineers (
id integer NOT NULL REFERENCES people(id) ON DELETE CASCADE ON UPDATE CASCADE UNIQUE,
created timestamp with time zone DEFAULT now() NOT NULL,
modified timestamp with time zone NULL,
login_name varchar NOT NULL UNIQUE,
PRIMARY KEY(id)
);
engineers
继承自people
,因为“id”列people
作为外键传递给engineers
。此列也定义为两个表中的主键。如果我想使用某人的电子邮件地址查询login_name,可以通过SQL:
SELECT p.email FROM engineers e
JOIN people p ON p.id = e.id
WHERE p.inactive = False AND e.login_name = 'john.smith';
如何使用SQLAlchemy的声明式样式建模此关系并执行类似的查询?似乎“Joined Table Inheritance”描述了我的使用场景,但我的表中没有鉴别器列。我也一直试图使用“Concrete Table Inheritance”,但我只是设法迷惑自己。
我很感激任何建议。谢谢!
这种表结构的原因是因为“人”可能是“工程师”,“会计师”或“测试者”(或三者的某种组合)。 people
表包含每个人共有的属性,例如姓名,电话,号码,雇用日期等。
engineers
表格中的“已创建”和“已修改”列未在people
之间共享;两列与每个表不同。这些并非绝对必要,它们只是默认添加到数据库中的每个表定义,并用于跟踪审计/日志记录的更改。
答案 0 :(得分:0)
你所拥有的内容并不清楚,因为你复制了一些列而不是其他列。
来自docs:
SQLAlchemy支持三种继承形式:单表继承,其中几种类型由单个表表示,具体表继承,其中每种类型的类都是由独立表和连接表继承表示,其中类层次结构在依赖表之间分解,每个类由其自己的表表示,该表仅包括该类本地的那些属性。
因为您复制了created
和modified
列,所以这是具体继承的候选者。但是,因为您希望Employee
是一个不完整的实体而没有来自Person
的列,所以这也是表继承的连接。
我建议你尝试使其适合连接表继承,但我不完全确定映射器如何处理重复列的存在。在连接表继承中,可以将子类分别作为关系进行操作,但我不确定它们将如何合并,是否可以合并,或者可以使用哪种映射器配置来处理使用哪一个。如果有办法,this section可能会告诉你如何。
然而,这是让你入门的东西。 polymorphic_on
can also be any sql expression (scroll down to the polymorphic_on argument) - 它不必是一个列。如果您的唯一子类是engineers
表,则在鉴别器中使用EXISTS
子查询。
下面是一些未经测试的代码,如果不稍微搞乱它可能无法正常工作 - 它只是向您展示了您必须使用的模式。
people_table = Table('people', metadata,
Column('id', Integer, primary_key=True),
Column('email', String, unique=True),
Column('inactive', Boolean, default=False),
)
engineers_table = Table('engineers', metadata,
Column('id', Integer, ForeignKey('people.id'), primary_key=True),
Column('engineer_info', String),
)
class Person(object):
pass
class Engineer(Person):
pass
discriminator = case(
[
(exists().where(people_table.c.id==engineers_table.c.id), 'engineer'),
], else_='person')
mapper(Person, people_table, polymorphic_identity='person', polymorphic_on=discriminator)
mapper(Engineer, engineer_table, polymorphic_identity='engineer')
毋庸置疑,如果可能的话,你应该为自己的理智而努力:
person
表格中添加一个鉴别器列。created
表格中的modified
和engineer
列。