一、继承
1、对象模型继承
odoo对象模型继承有二种机制,传统继承和委托继承。
第一个继承机制允许模块修改另一个模块中定义的模型的行为:
- 向模型添加字段
- 覆盖模型上字段的定义,
- 向模型添加约束,
- 向模型添加方法
- 覆盖模型上的现有方法。
第二种继承机制(委托)允许将模型的每个记录链接到父模型中的记录,并提供对父记录的字段的透明访问。
分别使用关键字
_inherit
_inherits
教程使用传统继承的方法,在模型Partnet上增加一个instructor的布尔值属性,以标注是否为讲师;增加一个多对多的关联属性管理场次和参与者的关系session_ids。
增加文件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)
为显示继承的对象模型,需同步使用视图继承。
2、视图继承
Odoo无需修改现有视图(通过覆盖它们),而是提供视图继承,其中子级“扩展”视图被应用到根视图之上,并且可以从其父级添加或删除内容。
扩展视图使用inherit_id
字段引用其父视图,而不是单个视图,它的arch
字段由任意数量的xpath
元素组成,这些 元素选择和更改其父视图的内容。
expr
在父视图中选择单个元素的XPath表达式。如果不匹配元素或不匹配元素,则引发错误
position
应用于匹配元素的操作:
inside
xpath
在匹配元素的末尾附加的主体
replace
用xpath
的主体替换匹配的元素,用$0
原始元素替换新主体中出现的任何节点
before
xpath
在匹配的元素之前将的正文作为同级插入
after
xpaths
在匹配的元素之后将的正文作为同级插入
attributes
变造使用特殊的匹配元素的属性 attribute
的元素的xpath
的主体
增加文件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>
<!--view inheritance -->
<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>
在__init__.py文件中导入partner
# -*- coding: utf-8 -*-
from . import controllers
from . import models
from . import partner
在__manifest__.py文件中,包含partner.xml
# always loaded
'data': [
'security/ir.model.access.csv',
#'views/views.xml',
#'views/templates.xml',
'views/openacademy.xml',
'views/partner.xml',
],
在应用中,更新openacademy模块后,可以看到partner中新增加的二个属性
二、计算属性和默认值
1、依赖
在session对象模型中增加一个计算属性上座率,并以过程条的形式显示在视图中。
在models.py文件中的session对象中增加taken_seats属性
attendee_ids = fields.Many2many('res.partner', string="Attendees")
#依赖其他属性值的计算属性taken_seats
taken_seats = fields.Float(string="Taken seats", compute='_taken_seats')
@api.depends('seats', 'attendee_ids')
def _taken_seats(self):
for r in self:
if not r.seats:
r.taken_seats = 0.0
else:
r.taken_seats = 100.0 * len(r.attendee_ids) / r.seats
在openacademy/views/openacademy.xml文件中,session视图中增加taken_seats过程条
<group string="Schedule">
<field name="start_date"/>
<field name="duration"/>
<field name="seats"/>
<field name="taken_seats" widget="progressbar"/>
</group>
<!--
...
-->
<tree string="Session Tree">
<field name="name"/>
<field name="course_id"/>
<field name="taken_seats" widget="progressbar"/>
</tree>
更新openacademy模块后,session视图运行效果为
2、默认值
为对象属性提供一个默认的初始化值。
设定session的start_day的默认值为当天,座位数为45,增加active属性默认傎为True
修改openacademy/models/models.py中session对象
class Session(models.Model):
_name = 'openacademy.session'
_description = "OpenAcademy Sessions"
name = fields.Char(required=True)
start_date = fields.Date(default=fields.Date.today) #默认当天
duration = fields.Float(digits=(6, 2), help="Duration in days")
seats = fields.Integer(string="Number of seats",default=45) #默认45座位
active = fields.Boolean(default=True) #默认True
运行效果如下
3、动态更新
当参与人数超过座位数时告警。
修改openacademy/models/models.py中session对象
#检查座位数和到场人数之间的限制
@api.onchange('seats', 'attendee_ids')
def _verify_valid_seats(self):
if self.seats < 0:
return {
'warning': {
'title': "Incorrect 'seats' value",
'message': "The number of available seats may not be negative",
},
}
if self.seats < len(self.attendee_ids):
return {
'warning': {
'title': "Too many attendees",
'message': "Increase seats or remove excess attendees",
},
}
运行效果
4、模型约束
Odoo提供了两种方法来设置自动验证: Python constraints
和 SQL constraints
。
session中增加一个python约束,讲师不能作为自己课堂的听众。
#instructor和attendee角色不能在同一个session中出现
@api.constrains('instructor_id', 'attendee_ids')
def _check_instructor_not_in_attendees(self):
for r in self:
if r.instructor_id and r.instructor_id in r.attendee_ids:
raise exceptions.ValidationError("A session's instructor can't be an attendee")
增加一个sql约束,course名不能相同
_sql_constraints = [
('name_description_check',
'CHECK(name != description)',
"The title of the course should not be the description"),
('name_unique',
'UNIQUE(name)',
"The course title must be unique"),
]
参考文档
https://www.odoo.com/documentation/13.0/howtos/backend.html#build-an-odoo-module