简体   繁体   English

使用SQLAlchemy为这种继承建模的正确方法是什么?

[英]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! 谢谢!

Edited 已编辑

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. 您在这里所拥有的不是任何一种类型,因为您重复了一些列,但没有重复其他列。

From the docs : 文档

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. 因为您复制了createdmodified列,所以这是具体继承的候选对象。 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: 不用说,如果有可能,您应该出于自己的理智:

  1. Add a discriminator column to your person table. 在您的person表中添加一个鉴别符列。
  2. Get rid of the created and modified columns in the engineer table. 摆脱engineer表中createdmodified列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 TaggedBlogRecord模型在sqlalchemy中继承时缺少什么才能正常工作? - What is missing in the TaggedBlogRecord model for inheritance in sqlalchemy for it to work? SQLAlchemy:将当前会话包装到模型中的正确方法? - SQLAlchemy: proper way to wrap the current session into a model? 存储大字符串的正确SQLAlchemy类型是什么? - What is the proper SQLAlchemy Type to store big strings? SQLAlchemy-模型简单继承 - SQLAlchemy - model simple inheritance SQLalchemy以声明方式描述关联对象的正确方法是什么 - What's the proper way to describe an associative object by SQLalchemy the declarative way 在 SQLAlchemy (Python) 中联合查询列表的正确方法是什么? - What's the proper way to UNION a list of queries in SQLAlchemy (Python)? 在 Flask SQLALchemy 模型中处理业务逻辑的正确方法是什么? - What's the proper way of handling business logic in Flask SQLALchemy models? 在SQLAlchemy中使用外键插入对象的正确方法是什么? - What is the proper way to insert an object with a foreign key in SQLAlchemy? 测试抛出IntegrityError的SQLAlchemy代码的正确方法是什么? - What is a proper way to test SQLAlchemy code that throw IntegrityError? 将 SQLAlchemy 会话与 Celery 一起使用的正确方法是什么? - What's the proper way to use SQLAlchemy Sessions with Celery?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM