2013-02-01 85 views
2

這個問題或許比最初看起來更復雜。如何將繼承對象作爲OpenERP中的子類處理?

假設我有一個父類Animal(我們在OpenERP中將其命名爲animal.base)。我也有獅子(animal.lion)和大象(animal.elephant)的小類。我需要能夠創建一個可以引用Animal的任何子類的many2one字段的視圖。這似乎做以下工作:

class animal_lion(osv.osv): 
    _name = 'animal.lion' 
    _inherits = {'animal.base': 'base_id'} 

    _columns = { 
     ... 
     'base_id': fields.many2one('animal.base', "Base ID") 
    } 

    def roar(self, cr, uid, context=None): 
     print "rarrrrr" 

現在,當我們創建的animal.lion一個實例,我們可以看到它是在引用animal.base觀點可見。 (Plain inherit = 'animal.base'不表現這種方式,FWIW。)

但是,現在讓我們假設我們需要使用這種動物的方法。由於many2one簡單地指animal.base,我們不知道用戶在視圖中選擇了哪種動物。即使我們碰巧知道只有獅子會被選中,我們也不能撥打roar,因爲animal.base對象只會讓我們調用自己定義的方法。我們可以嘗試通過命名方法emit_sound並嘗試重寫Lion類中的方法來解決此問題。這至少會運行(除了_inherits之外,您還添加了_inherit),但它不會生成正確的Lion特定輸出。現在需要的是一些方法來確定基類x上many2one中選擇的特定實例的動態類型,其中多個子類在同一類x上指定_inherits。想象一下虛構的方法get_subtype()。然後,我們可以說,在我們的按鈕處理程序視圖:

def perform(self, cr, uid, ids, context=None): 
    this = self.browse(cr, uid, ids[0], context) 
    subtype_name = this.my_many2one.get_subtype() 
    subtype = self.pool.get(subtype_name) 
    # will produce a roar if user picked a lion, else a meep 
    subtype.emit_sound(cr, uid, context) 

另外,有可用於完成相同的任務的任何其他架構? (是的,我設計了這個例子,但它應該說明真正的問題。)[也許在每個子類型實例的字段中編碼子類型名稱? ]

我只限於OpenERP v5,但有興趣知道任何版本的答案。

回答

4

這裏的關鍵是您希望您的base.animal作爲所有動物的共同索引獨立存在於數據庫中,因此這大大增加了數據模型的複雜性並迫使您使用記錄級繼承(通過_inherits)。

爲了解決動物的亞型,您應該在animal.base中添加明確的type列,並且始終正確設置它,以便您可以推斷子類型記錄。

# This static list could also be replaced by a function 
ANIMALS = [ 
    ('lion', 'Lion'), 
    ('elephant', 'Elephant'), 
] 
class animal_base(osv.osv): 
    _name = 'animal.base' 
    _columns = { 
     ... 
     'type': fields.selection(ANIMALS, 'Type'), 
    } 

base.animals將存在於自己的數據庫中,可以有自己的看法,因爲你正在使用記錄級繼承。 子類型(例如獅子)可以看作是每隻動物的「裝飾」,並且它可能實際上不是唯一的(對於相同的base.animal記錄,​​和base.elephant記錄都可以存在),所以您應該添加唯一性約束某處。

現在,您不應該同時指定_inherit_inherits指向同一個父模型,這兩個繼承方案實際上是爲了不同的目的,如OpenERP technical memento中所述。 相反,你可以在animal.base代理的方法大致會看起來像你的perform方法,除非他們需要找出的子記錄的ID除了自己的類型,例如:

def emit_sound(self, cr, uid, ids, context=None): 
    for this in self.browse(cr, uid, ids, context): 
     animal_registry = self.pool['animal.%s' % this.type] 
     animal_ids = animal_registry.search(cr, uid, 
      [('base_id','=',this.id)], context) 
     assert len(animal_ids) == 1, 'Chimera alert! ;-)' 
     animal_registry.emit_sound(cr, uid, animal_ids, context) 

當然,你可以細化這可以通過幾種方式實現,例如將功能字段添加到base.animal中以自動執行更多此管道工作。


在另一方面,如果你不真的需要base.animal旁邊等真實動物存在,只是需要一種方法來選擇表單視圖的任意動物,你可以嘗試使用_inherit + _name的傳統繼承,base.animal是它們的抽象基類(沒有實際保存任何記錄)。 選擇一個任意的動物可以通過fields.reference完成,您可以在其中篩選目標模型列表。 5.0 subscription模塊包含an example with the doc_source field
小心,fields.reference是一種混合物,它不能與例如browsereadsearch。它以'model,id'的形式存儲爲一個字符串,並且每當需要對其進行解引用時都必須手動分割值 - 因此,如果走這條路,請小心。它被集成爲僞many2one的唯一地方是在客戶端UI上,在其他地方它只是一個簡單的啞巴字符串值。