2013-05-06 44 views
0

我有一對看起來有點像這樣(簡化的示例)的PostgreSQL表:從people用SQLAlchemy對這種類型的繼承進行建模的正確方法是什麼?

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繼承因爲「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表包含共同的每一個人的屬性,諸如姓名,電話,數字,租賃日期等

「創建」和在engineerspeople之間不共享「修飾的」列;這兩列對每個表都是不同的。這些不是絕對必要的,它們只是默認添加到數據庫中的每個表定義中,並用於跟蹤用於審計/日誌記錄目的的更改。

回答

0

你在這裏有什麼不明確的類型,因爲你重複一些列而不是其他人。

docs

SQLAlchemy的支持三種形式的繼承:單表繼承,其中多種類型的類由一個單一的表來表示,混凝土表繼承,每種類型的類別的其中由獨立表格表示,並且聯合表格繼承,其中類別層次結構在相關表格之間分解,每個類別由其自己的表格表示,該表格僅包括那些類別的本地屬性。

由於您複製了createdmodified列,因此這是具體繼承的候選項。但是,因爲您預期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') 

不用說,如果這是在所有可能你應該,你自己的理智:

  1. 添加一個鑑別列到你的person表。
  2. 擺脫engineer表中的createdmodified列。
+0

哇。感謝您的詳細回覆。我編輯了這個問題來解決點#1和#2。明天早上我會花更多的時間用你的例子。 – jamieb 2013-05-06 05:15:52

相關問題