2

この質問は、おそらく最初に思われるよりも複雑です。

親クラス Animal があるとしましょう (OpenERP では と名付けますanimal.base)。サブクラス Lion ( animal.lion) と Elephant ( 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。(Plaininherit = 'animal.base'はこのようには動作しません、FWIW.)

ただし、この動物のメソッドを使用する必要があるとしましょう。many2one は単に を参照しanimal.baseているため、ユーザーがビューで選択した動物の種類はわかりません。たまたまライオンだけが選ばれることがわかっていたとしても、呼び出すことはできませんroar。なぜなら、animal.baseオブジェクトはそれ自体で定義されたメソッドしか呼び出せないからです。emit_soundメソッドに名前を付け、Lion クラスでメソッドをオーバーライドしようとすることで、ハッキングを試みることができます。これは少なくとも ( に加えて を追加すると) 実行されます_inherit_inherits、正しい Lion 固有の出力は生成されません。必要なのは、同じクラスxで複数のサブクラスが指定されているベース クラスの many2one で選択された特定のインスタンスの動的な型を特定する方法です。_inheritsx. 架空のメソッドを想像してみてください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

1 に答える 1

4

ここで重要なのはbase.animal、すべての動物の共通インデックスとしてデータベース内に単独で存在するようにすることです。これにより、データ モデルが大幅に複雑になり、レコード レベルの継承 ( を使用_inherits) を使用する必要があります。

動物のサブタイプを解決するには、明示的なtype列を に追加しanimal.base、常に適切に設定して、サブタイプ レコードを推測できるようにする必要があります。

# 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.liona とレコードの両方が存在する可能性があります)、一意性制約をどこかに追加する必要があります。base.elephantbase.animal

OpenERP Technical memento_inheritで説明されているように、これら 2 つの継承スキームは実際には異なる目的のために意図されています。代わりに、タイプに加えて子レコードの ID を見つける必要があることを除いて、メソッドとほぼ同じように見えるプロキシ メソッドを に含めることができます。_inheritsanimal.baseperform

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.0subscriptionモジュールには、フィールドの例がdoc_source含まれています。
気をつけてください、は、や などfields.referenceとシームレスに統合されないハイブリッドなものです。フォームに文字列として格納されますbrowsereadsearch'model,id'逆参照する必要があるときはいつでも、値を手動で分割する必要があります。そのため、そのパスに行く場合は注意してください。疑似として統合されている唯一の場所many2oneはクライアント UI であり、それ以外の場所では、単純な単純な文字列値です。

于 2013-02-01T15:48:52.453 に答える