Расширение Odoo и наследование

Odoo имеет три типа наследования, и у меня есть как минимум такое количество вопросов.

1. "Нормальное" наследование (_inherit)

Для меня это относительно интуитивно понятно, но почему бы им просто не сделать это питоническим способом:

ChildClass(ParentClass):

Почему у них есть (вроде бы эквивалент):

ChildClass(model.Model):
     _inherit = 'module.parentclass'

2. Расширение

Для меня это не имеет смысла (в том смысле, что я не знаю, зачем вы его использовали), пример ниже, но может ли кто-нибудь дать мне практический пример использования. http://www.odoo.com/documentation/9.0/reference/orm.html#extension

3. Делегирование (_inherits)

Для меня это тоже не имеет смысла, это похоже на несколько подклассов, но только полей, а не методов.

ВОПРОС

  1. Почему существует _inherit, какие преимущества / отличия по сравнению с обычным подклассом?

  2. Когда / зачем вам продлевать? Думаю, у меня есть идея, но уверен, что кто-то другой сможет выразить яснее.

  3. Может немного чего, почему про _inherits


person amchugh89    schedule 13.07.2016    source источник


Ответы (3)


Я просто возился с наследованием, ниже приведены примеры «классического» наследования odoo (передать _inherit и _name дочернему элементу) и odoo «extension», передать только _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)

КОНСОЛЬ

>>> 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  

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' 

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'

Модель расширения на самом деле не существует (не имеет имени, и вы не можете создать ее экземпляр), она просто добавляет материал к родительскому элементу.

person amchugh89    schedule 14.07.2016

Хорошо, я объясню это.

Традиционное наследование в Python не расширяет базовый класс. Итак, если вы расширите A от B, тогда A будет объектом типа A и B. Если вы создаете объект типа B. Не будет ничего от A. Было бы смешно иметь что-то вроде этого:

SortedDict(dict)
RandomDict(dict)
.... 

И тогда dict стал _9 _, _ 10 _...

Для python, поскольку вы расширяете то, что хотите, вам необходимо импортировать конкретный класс, из которого вы хотите расширить, и при необходимости использовать этот конкретный новый класс. На практике в Python мы не расширяем много классов, поскольку в большинстве случаев в этом нет необходимости.

Теперь об одоо.

  1. Odoo _inherit

Odoo состоит из модулей очень много модулей. Если нам нужно знать каждую модель, которая была унаследована для расширения конкретной модели. Нам пришлось бы изменить представления, чтобы они ссылались на последнюю расширенную модель ... Было бы сложно указать, какой класс использовать.

Решение простое: сделайте всю модель наследником ModelClass. Внутри определения класса сохраните инструкцию, которая сообщает odoo, какую модель базы данных следует расширить. Мы можем ссылаться в наших представлениях на одну единственную модель, и odoo позаботится о наследовании модели (а не о наследовании классов) во время выполнения. Это позволит нам использовать super в методах для вызова методов, определенных в определениях родительской модели ... Приятно то, что нам не нужно знать BaseClass, в котором расположен метод. В противном случае нам нужно было бы знать конкретный класс, у которого есть модель, но поскольку модули могут быть добавлены / удалены, невозможно узнать, какой класс является последним в цепочке наследования модели. Вот почему _inherit в значительной степени необходим. Мы создаем подклассы не классов, а моделей. Это не совсем питонический, но если бы мы хотели сделать его питоническим, нам пришлось бы неявно расширить модель с помощью синтаксического сахара (который также не совсем питонический) ... Так что технически явное определение того, какую модель мы хотим расширить, является более питоническим чем при использовании стандартной схемы наследования классов. Если подумать, в этом есть смысл.

  1. Почему используется расширение

Я в значительной степени это объяснил. Но вы должны понимать, что множество модулей можно загружать в неопределенном порядке. Вот почему расширение имеет смысл. Методы могут вызываться в разном порядке, но все равно все должно работать правильно. Если у вас загружено несколько модулей, ваш код все равно должен работать, когда модуль, о котором вы никогда не знали, будет добавлен в odoo. Способ работы наследования не является полностью недетерминированным, но в некоторых случаях порядок загрузки может отличаться на некоторых компьютерах / серверах.

  1. _inherits имеет большой смысл.

Это самое близкое к традиционному наследованию классов Python для моделей.

Когда вы используете _inherits, дочерняя модель не расширяет базовую модель, от которой вы наследуете. Он используется для создания новой модели, которая не дублирует атрибуты родительской модели. Помните, мы создаем объекты базы данных. Сохраняется ссылка на родительский объект, содержащий дополнительные атрибуты. Один простой пример - это res.partner и res.user. Вкратце, res.user - это res.partner с логином и паролем ... Не имеет смысла добавлять логин / пароль ко всем res.partners, которые не являются пользователями ... И это вроде здорово чтобы иметь возможность повторно использовать весь пользовательский интерфейс res.partner для пользователей res.users. Если бы у odoo не было наследования, нам пришлось бы полностью дублировать пользовательский интерфейс / db res.partner для res.users ... и мы не могли бы легко использовать res.users там, где должен быть res.partner использовано .... Простое решение - сохранить идентификаторы разных моделей и сохранить ссылку ... Но было бы здорово иметь доступ к "user.name" вместо "user.partner_id.name". Очевидно ... В Python вы не пишете ... "obj.super.property", чтобы получить доступ к свойствам родительского класса? Технически здесь то же самое. поля делегируются ...

Теперь почему методы не делегируются? Я предполагаю, что это в значительной степени связано с проблемой с делегатами в множественном наследовании. Если вы _унаследуете несколько моделей, которые имеют приоритет над write или _14 _... К какой из них вы будете звонить? Технически ни один из методов не должен вызываться, потому что они определены в родительском объекте. Поэтому, если вы хотите вызвать метод res.partner для объекта res.users, self, который будет отправлен родительскому методу, будет res.user, а не _18 _... Что вызовет проблемы, поскольку res.partner не ожидает, что он будет называется res.users. Даже если вы вызовете метод "res.partner" со ссылкой partner_id ... Тогда откуда, черт возьми, вы знаете, что значения, переданные в res.users, действительно должны быть переданы res.partner? По этой причине безопаснее явно вызывать нужные методы с partner_id.write с явными значениями, которые вы хотите отправить. Для атрибутов не очень важно знать, какой атрибут будет использоваться. Теоретически это довольно детерминировано. Я не пробовал, но есть вероятность, что запись для атрибута будет делегирована конкретному родителю в зависимости от порядка, в котором создаются поля делегата. Dict, в котором хранится запись _inherits, будет возвращать значения в определенном порядке. И поскольку вы все время будете читать / писать из одного и того же объекта, в большинстве случаев не имеет значения, какой родитель будет владеть данными, если существуют повторяющиеся атрибуты. Также есть возможность добавить больше делегированных полей или указать конкретное поле для делегирования, так что технически здесь нет проблем. Но для методов, как я объяснил, вы не можете ожидать, что odoo будет знать, какой метод следует делегировать, а какой нет, поэтому лучше перестраховаться и явно попросить программиста сказать, что делать.

person Loïc Faure-Lacroix    schedule 27.03.2017

_inherit

Хотя этот термин появляется на картинке, он означает, что вы собираетесь что-то расширить до текущей модели. Какие бы поля и методы вы ни описали, они будут добавлены к той модели, которую вы указали в _inherit.

_inherits

Это интересная концепция, которая будет определять другую модель, которая может получить доступ ко всем этим свойствам и методам родительской модели без ссылки на объект, это означает, что все те поля и методы, которые есть в родительской модели, будут напрямую доступны через объект дочернего класса и обе модели. будут подключены через ссылку Many2one => One2many, которую необходимо указать дополнительно.

Все эти поля не будут физически клонированы в дочернюю модель, но она будет там, пока мы сможем получить к ней доступ через ее объект только из-за _inherits.

Пример

_inherit

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

    field_name = fields.Char("Title")

_inherits

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), 
     }

Если вы подумаете о нормальном питоническом способе, который предоставит любые способы обновления поведения родительского класса, а дополнительные вещи будут доступны только через родительский объект. При обычном наследовании мы можем добавлять поля и методы, но все они будут доступны только через объект дочернего класса.

person Emipro Technologies Pvt. Ltd.    schedule 14.07.2016
comment
Извините, но это не отвечает на мои вопросы - отличается ли _inherit от обычного наследования? И я почти уверен, что ваше объяснение _inherits просто неверно - person amchugh89; 14.07.2016
comment
Подскажите, пожалуйста, как? Прочтите последние строки ответа, это о разнице. - person Emipro Technologies Pvt. Ltd.; 14.07.2016
comment
_inherit отличается от обычного наследования? - person amchugh89; 14.07.2016
comment
Вы: Если вы думаете о нормальном питоническом способе, который предоставит любые способы обновления поведения родительского класса, а дополнительные вещи будут доступны только через родительский объект. <-- Неа - person amchugh89; 14.07.2016
comment
да, это отличается от нормального наследования, у odoo есть расширенное наследование и создана функция под названием_inherit. - person Emipro Technologies Pvt. Ltd.; 14.07.2016
comment
Если вы подумаете о нормальном питоническом способе, который предоставит любые способы обновления поведения родительского класса, а дополнительные вещи будут доступны только через родительский объект. = ›Это делается odoo только из-за _inherit. - person Emipro Technologies Pvt. Ltd.; 14.07.2016