🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 继承 [TOC] #### 模型继承 Odoo提供两种继承机制,以模块化方式扩展现有模型。 第一种继承机制允许一个模块修改另一个模块中定义的模型的行为。 * 给模型添加字段 * 覆盖模型现有字段 * 给模型添加约束 * 给模型添加方法 * 覆盖模型现有方法 第二种继承机制(委托)允许将模型的每条记录链接到父模型的记录,并且提供对父记录的透明访问。 #### 视图继承 Odoo不是通过覆盖来修改现有视图,而是通过视图继承。子视图不仅能够修改继承至父视图的自身内容,而且能够修改和删除父视图中的内容。 扩展视图使用`inherit_id`字段引用其父代,而不是单个视图,其`arch`字段由任意数量的`xpath`元素组成,选择和更改其父视图的内容: ~~~ <!-- improved idea categories list --> <record id="idea_category_list2" model="ir.ui.view"> <field name="name">id.category.list2</field> <field name="model">idea.category</field> <field name="inherit_id" ref="id_category_list"/> <field name="arch" type="xml"> <!-- find field description and add the field idea_ids after it --> <xpath expr="//field[@name='description']" position="after"> <field name="idea_ids" string="Number of ideas"/> </xpath> </field> </record> ~~~ *expr* 在父视图中选者单个元素的*XPath*表达式。如果没有匹配到元素或者匹配到多个元素则引发错误。 *position* 对匹配到的元素进行操作。   *inside*   在匹配元素的末尾追加   *before*   作为匹配元素的同级元素添加在其后面   *after*   作为匹配元素的同级元素添加在其前面   *replace*   替换匹配的元素   *attributes*   使用新的属性替换匹配元素的属性 > 提示 > 当匹配单个元素时,`position`可以直接在匹配的元素上设置属性。下面的两个继承将给出相同的结果: ~~~ <xpath expr="//field[@name='description']" position="after"> <field name="idea_ids" /> </xpath> <field name="description" position="after"> <field name="idea_ids" /> </field> ~~~ > 练习更改现有内容 > > * 使用模型继承,修改现有*partner*模型,添加`instructor`布尔字段,以及对应表示"授课-讲师"关联的*many2many*字段 > * 使用视图继承在*partner*的表单视图中显示这个字段 > > > 注意,这里是通过开发人员模式来查找视图外部ID并放置新字段的。 > > > * 创建文件`openacademy/models/partner.py`并将其导入`__init__.py` > * 创建文件`openacademy/views/partner.xml`并将其添加到`__manifest__.py` `openacademy/__init__.py` ~~~ # -*- coding: utf-8 -*- from . import controllers from . import models from . import partner ~~~ `openacademy/__manifest__.py` ~~~ # 'security/ir.model.access.csv', 'templates.xml', 'views/openacademy.xml', 'views/partner.xml', ], # only loaded in demonstration mode 'demo': [ ~~~ `openacademy/partner.py` ~~~ # -*- coding: utf-8 -*- from odoo import fields, models class Partner(models.Model): _inherit = 'res.partner' # Add a new column to the res.partner model, by default partners are not # instructors instructor = fields.Boolean("Instructor", default=False) session_ids = fields.Many2many('openacademy.session', string="Attended Sessions", readonly=True) ~~~ `openacademy/views/partner.xml` ~~~ <?xml version="1.0" encoding="UTF-8"?> <odoo> <data> <!-- Add instructor field to existing view --> <record model="ir.ui.view" id="partner_instructor_form_view"> <field name="name">partner.instructor</field> <field name="model">res.partner</field> <field name="inherit_id" ref="base.view_partner_form"/> <field name="arch" type="xml"> <notebook position="inside"> <page string="Sessions"> <group> <field name="instructor"/> <field name="session_ids"/> </group> </page> </notebook> </field> </record> <record model="ir.actions.act_window" id="contact_list_action"> <field name="name">Contacts</field> <field name="res_model">res.partner</field> <field name="view_mode">tree,form</field> </record> <menuitem id="configuration_menu" name="Configuration" parent="main_openacademy_menu"/> <menuitem id="contact_menu" name="Contacts" parent="configuration_menu" action="contact_list_action"/> </data> </odoo> ~~~ #### Domain Odoo中,Domain代表记录集的条件表达式。Domain是定义模型子集的规则集合。每个规则是一个包含名称、操作和值的三元组。例如,下面是*Product*模型子集的Domain表达式,“单价大于1000且类型为服务”的记录集: ~~~ [('product_type', '=', 'service'), ('unit_price', '>', 1000)] ~~~ 多个规则组合时,默认条件组合方式是AND。逻辑运算符`&(AND)`,`|(OR)`,`!(NOT)`可以用来显示的组合多个规则。它们在前缀位置使用(操作符在参数之前,而不是中间)。例如下面的Domain表达式,含义是"类型为服务或者单价不介于1000和2000之间" ~~~ ['|', ('product_type', '=', 'service'), '!', '&', ('unit_price', '>=', 1000), ('unit_price', '<', 2000)] ~~~ 当在客户端界面选择记录集时,`domain`参数可以添加到关联字段上,以限制只显示有效的关联字段。 > 练习在关联字段上使用Domain,当为授课选择讲师时,只有`instructor`值为`True`的讲师会被显示出来。 `openacademy/models.py` ~~~ duration = fields.Float(digits=(6, 2), help="Duration in days") seats = fields.Integer(string="Number of seats") instructor_id = fields.Many2one('res.partner', string="Instructor", domain=[('instructor', '=', True)]) course_id = fields.Many2one('openacademy.course', ondelete='cascade', string="Course", required=True) attendee_ids = fields.Many2many('res.partner', string="Attendees") ~~~ > 注意 > 声明为文字列表的domain会在服务端进行计算,不会出现在右侧的动态列表中,而声明为字符串的domain是在客户端进行计算的,字段名将出现在右侧列表。 > > 练习更复杂的domain,创建新的*partner*类别*Techer/Level1*和*Techer/Level2*.一个授课的教授人可以是讲师或者任意级别的教师。 > > * 修改*Session*模型的domain > * 修改`openacademy/view/partner.xml`以获得访问*Partner*类别的入口。 `openacademy/models.py` ~~~ seats = fields.Integer(string="Number of seats") instructor_id = fields.Many2one('res.partner', string="Instructor", domain=['|', ('instructor', '=', True), ('category_id.name', 'ilike', "Teacher")]) course_id = fields.Many2one('openacademy.course', ondelete='cascade', string="Course", required=True) attendee_ids = fields.Many2many('res.partner', string="Attendees") ~~~ `openacademy/views/partner.xml` ~~~ <menuitem id="contact_menu" name="Contacts" parent="configuration_menu" action="contact_list_action"/> <record model="ir.actions.act_window" id="contact_cat_list_action"> <field name="name">Contact Tags</field> <field name="res_model">res.partner.category</field> <field name="view_mode">tree,form</field> </record> <menuitem id="contact_cat_menu" name="Contact Tags" parent="configuration_menu" action="contact_cat_list_action"/> <record model="res.partner.category" id="teacher1"> <field name="name">Teacher / Level 1</field> </record> <record model="res.partner.category" id="teacher2"> <field name="name">Teacher / Level 2</field> </record> </data> </odoo> ~~~ 作者:luohuayong 链接:http://www.jianshu.com/p/fd0617835b48 來源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。