[英]What is the proper way to model this type of inheritance with SQLAlchemy?
I have a pair of PostgreSQL tables that look somewhat like this (simplified example): 我有一对看起来像这样的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
inherits from people
because the "id" column people
passes through to engineers
as a foreign key. engineers
从继承people
,因为“ID”列people
通过以engineers
为外键。 This column is also defined as a primary key in both tables. 该列在两个表中也都定义为主键。 If I wanted query the login_name using someone's email address, it could be done like this via SQL:
如果我想使用某人的电子邮件地址查询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';
How do I model this relationship using SQLAlchemy's declarative style and perform a similar query? 如何使用SQLAlchemy的声明样式对这种关系进行建模并执行类似的查询? It seems like " Joined Table Inheritance " describes my usage scenario, but I don't have a discriminator column in my tables.
似乎“ Joined Table Inheritance ”描述了我的使用情况,但是我的表中没有discriminator列。 I've also been trying to use " Concrete Table Inheritance " but am just managing to confuse myself.
我也一直在尝试使用“ Concrete Table Inheritance ”,但只是在使自己困惑。
I'd appreciate any suggestions. 我将不胜感激任何建议。 Thanks!
谢谢!
The reason this table structure is the way it is is because a "person" might be an "engineer", "accountant", or "tester" (or some combination of the three). 该表结构之所以如此,是因为“人”可能是“工程师”,“会计”或“测试员”(或这三者的某种组合)。 The
people
table contains the attributes that are common to everyone, such as a name, phone, number, date of hire, etc. people
表包含每个人都共有的属性,例如姓名,电话,电话号码,雇用日期等。
The "created" and "modified" columns on the engineers
table are not shared between people
; engineers
表上的“创建”和“修改”列不会在people
之间共享; the two columns are distinct to each table. 两列对于每个表都是不同的。 These aren't absolutely necessary, they're just added by default to each table definition in the database and are used to track changes for audit/logging purposes.
这些不是绝对必要的,它们只是默认情况下添加到数据库中的每个表定义中,并用于跟踪更改以进行审核/记录。
What you have here is not clearly either type because you duplicate some columns but not others. 您在这里所拥有的不是任何一种类型,因为您重复了一些列,但没有重复其他列。
SQLAlchemy supports three forms of inheritance: single table inheritance , where several types of classes are represented by a single table, concrete table inheritance , where each type of class is represented by independent tables, and joined table inheritance , where the class hierarchy is broken up among dependent tables, each class represented by its own table that only includes those attributes local to that class.
SQLAlchemy支持三种继承形式: 单表继承 ,其中几种类型的类由单个表表示; 具体表继承 ,其中每种类型的类由独立表表示;以及联接表继承 ,其中类层次结构被分解。在相关表之间,每个类由其自己的表表示,该表仅包括该类本地的那些属性。
Because you duplicate the created
and modified
columns, this is a candidate for concrete inheritance. 因为您复制了
created
和modified
列,所以这是具体继承的候选对象。 However, because you expect Employee
to be an incomplete entity without columns from Person
, this is also joined table inheritance. 但是,由于您希望
Employee
是一个不完整的实体,而没有Person
列,所以这也被联接到表继承中。
I suggest you try to make this fit into joined table inheritance, but I'm not entirely sure how the mapper will handle the presence of duplicated columns. 我建议您尝试使它适合联接的表继承,但是我不完全确定映射器如何处理重复列的存在。 It is possible in joined table inheritance to manipulate the subclasses separately as relations, but I'm not sure how they will be merged, if they can be merged, or what mapper configuration is available to handle which one is used.
在联接表继承中可以将子类作为关系分别进行处理,但是我不确定如何将它们合并,是否可以合并或可以使用哪种映射器配置来处理哪个子类。 If there is a way, this section will probably show you how.
如果有办法, 本节可能会向您展示方法。
However here is something to get you started. 但是,这里有一些入门知识。
polymorphic_on
can also be any sql expression (scroll down to the polymorphic_on argument) --it doesn't have to be a column. polymorphic_on
也可以是任何sql表达式(向下滚动到polymorphic_on参数) -它不必是一列。 If your only subclass is the engineers
table, you use an EXISTS
subquery in your discriminator. 如果您的唯一子类是
engineers
表,则在区分EXISTS
中使用EXISTS
子查询。
Below is some untested code that will probably not work without messing with it a bit--it just shows you the pattern you'll have to use. 下面是一些未经测试的代码,如果不稍作改动,可能将无法正常工作,它只是向您显示了必须使用的模式。
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')
Needless to say, if it's at all possible you should, for your own sanity: 不用说,如果有可能,您应该出于自己的理智:
person
table. person
表中添加一个鉴别符列。 created
and modified
columns in the engineer
table. engineer
表中created
和modified
列。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.