Odoo 扩展和继承

amc*_*h89 8 python inheritance openerp odoo-9

Odoo 有三种类型的继承,我至少有那么多问题。

1.“正常”继承(_inherit)

这对我来说相对直观 - 但他们为什么不以 Pythonic 的方式做到这一点:

ChildClass(ParentClass):
Run Code Online (Sandbox Code Playgroud)

为什么他们有(看似等价的):

ChildClass(model.Model):
     _inherit = 'module.parentclass'
Run Code Online (Sandbox Code Playgroud)

2. 扩展

这对我来说毫无意义(因为我不知道你为什么要使用它),下面是一个例子,但谁能给我一个实际的用例。 http://www.odoo.com/documentation/9.0/reference/orm.html#extension

3.委托(_inherits)

这对我来说也没有意义,它似乎是一个多子类化,但只是字段,而不是方法。

  1. 为什么 _inherit 存在,与普通子类化相比有什么好处/区别?

  2. 你什么时候/为什么要延长?我想我有一个想法,但我相信其他人可以表达得更清楚。

  3. 也许有点什么,为什么 _inherits

Loï*_*oix 7

好的,我会解释一下。

Python 中的传统继承不会扩展基类。因此,如果您ABthen扩展,将是和A类型的对象。如果创建类型为. 它不会有任何东西。如果有这样的事情那就太荒谬了:ABBA

SortedDict(dict)
RandomDict(dict)
.... 
Run Code Online (Sandbox Code Playgroud)

然后 dict 变成SortedDict, RandomDict...

对于Python,由于您扩展了您想要的内容,因此您必须导入您想要扩展的特定类,并在必要时使用该特定的新类。实际上,在 python 中,我们不会扩展太多类,因为在大多数情况下这并不是真正必要的。

现在关于odoo。

  1. Odoo_继承

Odoo 由很多模块组成。如果我们必须知道已继承的每个模型才能扩展特定模型。我们必须更改视图以引用最后一个扩展模型......指定要使用哪个类将是一件痛苦的事情。

解决方案很简单:使所有模型都从 ModelClass 扩展。在类定义中,保留一条指令,告诉 odoo 应扩展哪个数据库模型。我们可以在我们的视图中引用一个模型,并且 odoo 在运行时负责模型继承(而不是类继承)。这将允许我们在方法中使用super来调用父模型定义中定义的方法...好处是我们不必知道该方法所在的 BaseClass。否则,我们必须知道具有模型的特定类,但由于可以添加/删除模块,因此不可能知道哪个类是模型继承链中的最新类。这就是为什么_inherit非常有必要。我们不是对类进行子类化,而是对模型进行子类化。它并不是真正的Pythonic,但如果我们想让它变得Pythonic,我们必须用语法糖隐式地扩展一个模型(这也不是真正的Pythonic)......所以从技术上讲,明确定义我们想要扩展的模型更Pythonic比使用标准类继承方案。仔细想想,这似乎很有道理。

  1. 为什么使用扩展

我已经解释得很清楚了。但您必须了解许多模块可以按不确定的顺序加载。这就是为什么扩展有意义。方法可能会以许多不同的顺序调用,但事情仍然必须正常工作。如果您加载了多个模块,当您不知道的模块将被添加到 odoo 时,您的代码仍然必须工作。继承的工作方式并非完全不确定,但在某些情况下,某些计算机/服务器上的加载顺序可能有所不同。

  1. _inherits 很有意义。

这是与模型的传统 Python 类继承最接近的东西。

当您使用 _inherits 时,子模型不会扩展您继承的基本模型。它用于创建一个不重复父模型属性的新模型。请记住,我们正在创建数据库对象。保留对哪个父对象包含更多属性的引用。一个简单的例子是 res.partner 和 res.user。简而言之,res.user 是一个带有登录名和密码的 res.partner...将登录名/密码添加到所有非用户的 res.partner 中是没有意义的...而且这很棒能够为 res.users 重用所有 res.partner UI。如果 odoo 没有继承,我们就必须为 res.users 完全复制 res.partner UI/db...并且我们无法在必须有 res.partner 的地方轻松使用 res.users使用....简单的解决方案是保持不同型号的东西并保留链接...但是能够访问“user.name”而不是“user.partner_id.name”不是很好吗?显然......在python中你不写......“obj.super.property”来访问父类属性?从技术上讲,这里也是一样的。字段正在被委托...

现在为什么不委托方法?我想这很大程度上与多重继承中的委托问题有关。如果您_继承多个覆盖writecreate...的模型,您将调用哪一个?从技术上讲,不应调用任何方法,因为它们是在父对象上定义的。因此,如果您想在对象上调用 res.partner 方法res.users,则self发送到父方法的将是 ares.user而不是 ares.partner... 这会导致问题,因为res.partner不希望被 a 调用res.users。即使您使用链接调用“res.partner”方法partner_id...那么您怎么知道传递给 的 valsres.users应该实际传递给res.partner?因此,使用partner_id.write要发送的显式值来显式调用所需的方法会更安全。对于属性来说,知道将使用哪个属性并不重要。从理论上讲,这是相当确定的。我还没有尝试过,但很可能对属性的写入将被委托给特定的父级,具体取决于创建委托字段的顺序。存储条目的字典_inherits将按确定的顺序返回值。而且由于您始终从同一个对象读取/写入,因此在大多数情况下,如果存在重复属性,哪个父对象将拥有数据并不重要。还可以添加更多委托字段或指定委托的特定字段,因此从技术上讲,这里没有问题。但对于方法,正如我所解释的,你不能真正期望 odoo 知道哪个方法应该被委托,哪个方法不应该被委托,所以最好谨慎行事并明确要求程序员告诉要做什么。


amc*_*h89 6

我一直在搞乱自己的继承,下面是odoo“经典”继承(将_inherit和_name传递给孩子)和odoo“扩展”的例子,只将_inherit传递给孩子

_inherits(委托)太古怪了,我什至不打算测试它。我不知道我会如何使用它 - 文档解释了如何使用(http://www.odoo.com/documentation/9.0/reference/orm.html#delegation)如果有人可以解释为什么会很好但我不会一直强调它。

楷模

class Parent(models.Model):
    _name = 'aidentest.parent'

    first = fields.Char()
    last = fields.Char()

    def call(self):
        return self.check(self.first)

    def check(self, s):
        return "name: {} familia: {}".format(s, self.last)

#normal inheritance of parent
class Child1(models.Model):
    _name = 'aidentest.child1'
    _inherit = 'aidentest.parent'

    first = fields.Char()

    def call(self):
        return self.check(self.first)


#this extends parent
class Child2(models.Model):
    #_name = 'aidentest.child2' #no name - "extension" of inherited model
    _inherit = 'aidentest.parent'

    middle = fields.Char()

    def call(self):
        return self.check(self.first)
Run Code Online (Sandbox Code Playgroud)

安慰

>>> p1 = self.env['aidentest.parent'].create({'first':'mr','last':'dad'})
>>> p1.read()
[{'create_uid': (1, u'Administrator'), 'create_date': '2016-07-14 13:54:23', 'display_name': u'aidentest.parent,3', '__last_update': '2016-07-14 13:54:23', 'write_uid': (1, u'Administrator'), 'middle': False, 'write_date': '2016-07-14 13:54:23', 'last': u'dad', 'id': 3, 'first': u'mr'}]
>>> p1.call()
'name: mr familia: dad'
>>> p1.middle
False  
Run Code Online (Sandbox Code Playgroud)

False 表示该字段存在(通过 Child2 的“扩展”,但未填充)否则我会收到属性错误

>>> c1 = self.env['aidentest.child1'].create({})
>>> c1.first
False
>>> c1.middle  
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'aidentest.child1' object has no attribute 'middle' 
Run Code Online (Sandbox Code Playgroud)

Child1 仅从基类继承,而不是从“扩展”基类继承 - 它忽略 Child2 对父类的扩展。Child2 通过添加“中间”字段扩展父级,Child1 无法访问该字段

>>> c2 = self.env['aidentest.child2'].create({})
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Users\mamwo\Desktop\odoo\openerp\api.py", line 768, in __getitem__
    return self.registry[model_name]._browse(self, ())
  File "C:\Users\mamwo\Desktop\odoo\openerp\modules\registry.py", line 84, in __getitem__
    return self.models[model_name]
KeyError: 'aidentest.child2'
Run Code Online (Sandbox Code Playgroud)

Extending 模型并不真正存在(没有名称,您无法实例化它),它只是向父模型添加内容。


Emi*_*td. 2

_继承

当这个术语出现时,它意味着您要将某些内容扩展到当前模型。您在那里描述的任何字段和方法都将附加到您在_inherit中指定的模型中中指定的模型中。

_继承

这是一个有趣的概念,它将定义另一个模型,该模型可以访问父模型的所有属性和方法,而无需引用对象,这意味着父模型中的所有字段和方法都可以通过子类对象和两个模型直接访问将通过 Many2one => One2many 引用连接,需要另外指定。

所有这些字段都不会物理地克隆到子模型中,但它会在那里,而我们可以通过它的对象访问它,只是因为 _inherits。

例子

_继承

class stock_picking(models.Model):
    _inherit='stock.picking'

    field_name = fields.Char("Title")
Run Code Online (Sandbox Code Playgroud)

_继承

class product_product(osv.osv):
    _name = "product.product"
    _inherits = {'product.template': 'product_tmpl_id'}

    _columns = {
       'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete="cascade", select=True, auto_join=True), 
     }
Run Code Online (Sandbox Code Playgroud)

如果您考虑正常的 pythonic 方式,它将提供任何更新父类行为的方法,并且其他内容只能通过父对象访问。在正常继承中,我们可以添加字段和方法,但所有这些都只能通过子类的对象访问。