Python 如何在OpenERP中将继承对象视为子类?

Python 如何在OpenERP中将继承对象视为子类?,python,openerp,Python,Openerp,这个问题可能比最初看起来更复杂 假设我有一个父类动物,我们在OpenERP中将它命名为Animal.base。我也有子类狮子动物。狮子和大象动物。大象。我需要能够创建一个具有多个字段的视图,该字段可以引用动物的任何子类。这似乎可以通过执行以下操作来实现: class animal_lion(osv.osv): _name = 'animal.lion' _inherits = {'animal.base': 'base_id'} _columns = {

这个问题可能比最初看起来更复杂

假设我有一个父类动物,我们在OpenERP中将它命名为Animal.base。我也有子类狮子动物。狮子和大象动物。大象。我需要能够创建一个具有多个字段的视图,该字段可以引用动物的任何子类。这似乎可以通过执行以下操作来实现:

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

然而,现在让我们假设我们需要使用这种动物的方法。由于manyOne只是指animal.base,我们不知道用户在视图中选择了哪种动物。即使我们碰巧知道只有狮子会被选中,我们也不能调用roar,因为animal.base对象只允许我们调用在其自身上定义的方法。我们可以尝试通过命名方法emit_sound并尝试在Lion类中重写该方法来绕过它。在_inherit之外添加_inherit后,至少会运行此操作,但它不会生成正确的特定于Lion的输出。需要的是某种方法来确定在基类x上的多个子类中选择的特定实例的动态类型,其中多个子类指定_继承同一类x。想象一个虚构的方法get_子类型。然后,我们可以在视图的按钮处理程序中说:

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作为所有动物的通用索引独立存在于数据库中,因此这会使您的数据模型大大复杂化,并迫使您通过_inherits使用记录级继承

为了解析动物的子类型,您应该在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将独立存在于数据库中,并且可以拥有自己的视图,因为您使用的是记录级继承。子类型(例如lion)可以被视为每种动物的装饰,它实际上可能不是唯一的。base.lion和base.elephant记录可能存在于同一base.animal记录中,因此您应该在某处添加唯一性约束

现在,您不应该让_inherit和_inherit都指向同一个父模型,这两个继承方案实际上用于不同的目的,如OpenERP中所述。 相反,您可以在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订阅模块包含。
注意,fields.reference是一种不能与浏览、阅读或搜索无缝集成的混合产品。它以“model,id”的形式存储为字符串,每当需要取消引用时,您都必须手动拆分该值-因此,如果使用该路径,请小心。它作为伪manyOne集成的唯一地方是在客户端UI上,在其他地方它只是一个简单的哑字符串值。

这里的关键是您希望base.animal在数据库中作为所有动物的通用索引独立存在,因此,这使您的数据模型大大复杂化,并迫使您通过_inherits使用记录级继承

为了解析动物的子类型,您应该在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将独立存在于数据库中,并且可以拥有自己的视图,因为您使用的是记录级继承。子类型(例如lion)可以被视为每种动物的装饰,它实际上可能不是唯一的。base.lion和base.elephant记录可能存在于同一base.animal记录中,因此您应该在某处添加唯一性约束

现在,您不应该让_inherit和_inherit都指向th 在相同的父模型中,这两个继承方案实际上是为了不同的目的,正如OpenERP中所解释的。 相反,您可以在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订阅模块包含。 注意,fields.reference是一种不能与浏览、阅读或搜索无缝集成的混合产品。它以“model,id”的形式存储为字符串,每当需要取消引用时,您都必须手动拆分该值-因此,如果使用该路径,请小心。它作为伪manyOne集成的唯一地方是在客户端UI上,而在其他地方,它只是一个简单的哑字符串值