这个问题可能比最初看起来更复杂。
假设我有一个父类 Animal(我们在 OpenERP 中将其命名为 animal.base
)。我还有子类 Lion (animal.lion
) 和 Elephant (animal.elephant
)。我需要能够创建一个具有可以引用 Animal 的任何子类的 Many2one 字段的 View 。这似乎可以通过执行以下操作来实现:
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
的 View 中可见。 (简单的 inherit = 'animal.base'
不会这样做,FWIW。)
但是,现在假设我们需要使用这种动物的方法。由于 Many2one 仅引用 animal.base
,因此我们不知道用户在 View 中选择了哪种动物。即使我们碰巧知道只有狮子会被选中,我们也不能调用 roar
因为 animal.base
对象只会让我们调用定义在本身。我们可以尝试通过命名方法 emit_sound
并尝试重写 Lion 类中的方法来绕过它。这至少会运行(除了 _inherits
之外添加一个 _inherit
后),但它不会产生正确的 Lion 特定输出。需要的是某种方法来确定在基类 x
上的 Many2one 中选择的特定实例的动态类型,其中多个子类在同一类 上指定
。想象一个虚构的方法 _inherits
>xget_subtype()
。然后我们可以在 View 的按钮处理程序中执行以下操作:
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,但有兴趣知道任何版本的答案。
最佳答案
这里的关键是您希望您的 base.animal
作为所有动物的公共(public)索引单独存在于数据库中,因此这会使您的数据模型变得非常复杂,并迫使您使用记录-级别继承(通过_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
将独立存在于数据库中,并且可以拥有自己的 View ,因为您使用的是记录级继承。 子类型(例如狮子)可以被视为每种动物的“装饰”,它实际上可能不是唯一的(base.lion
和 相同的
记录),因此您应该在某处添加唯一性约束。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
存在于其他真实动物旁边,而只是需要一种方法来选择表单 View 中的任意动物,您可以尝试使用传统继承 _inherit
+ _name
,其中 base.animal
是抽象基类为他们(没有实际持有任何记录)。
选择任意动物可以通过 fields.reference 来完成,您可以在其中过滤目标模型列表。 5.0 订阅
模块包含an example with the doc_source
field .
请注意,fields.reference
是一种混合体,不能与例如以下内容无缝集成: 浏览
、阅读
或搜索
。它以 'model,id'
形式存储为字符串,每当您需要取消引用它时,您都必须手动拆分该值 - 因此,如果您选择该路径,请务必小心。它作为伪 many2one
集成的唯一位置是在客户端 UI 上,其他地方它只是一个简单的、哑的字符串值。
关于python - 在 OpenERP 中如何将继承对象视为子类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14645832/