odoo(二)

odoo视图(view: tree, form, search, notebook),模型(models: Many2one, One2many, Many2many)

Menus docs

菜单也是用xml来配置

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!-- 如果有中文的话必须加上上面这个声明 -->
<odoo>
<record model="ir.actions.act_window" id="course_list_action"> 定义视图 </record> <menuitem 定义菜单/>
</odoo>
  • id识别用的,唯一
  • name在页面显示出来的文字
  • parent 上级菜单是谁(id
  • action 对应的菜单(属于一个集合)
  • sequence菜单的排序

Views docs

xml视图里面添加view的时候可以添加html标签,但必须是闭合的

继承

视图文档
Models继承差不多,多了inherits_id指向要改写的view

1
<field name="inherits_id" ref="id_tags_list" />

arch里面用xpath定位改写元素

Models docs

数据表模型,
先自己的models中重写别的models的时候需要在__manifest__.py把依赖关系,加入到自己模块的__manifest__.pydepends中。

Many2one直接关联已经存在的表(文章与分类的关系FK)| 单一的记录
One2many虚拟的关系()| 一系列的记录
Many2manyodoo 会再建立一张单独的关系表(一个文章多个标签,标签下多个文章)
ondelete='set null'如果关联的表删除了就把这个字段设置为空
ondelete='cascade'如果它关联Many2one的表被删除了,当前这表就会清空相关的全部数据
string 字段的别名
index 字段是否创建索引

1
name = fields.Char(
    string='Name',
    default=lambda self: self._get_default_name(),
)

@api.model
def _get_default_name(self):
    return "test"

PS: res.users可以登录的用户信息表;res.partner这张表里面的用户没有登录权限;res.users 可以对应到 res.partner 某条记录

继承和扩展

改写 Models

  • 经典继承
  • 原型继承(拷贝一个出来)
  • 委托继承
1
2
self.env.cr.commit()    # 提交数据
self.env['model'].search([]) # 取一条记录

  • inheritance视图(view),模型(models)的改写
  • domainmodels中过滤Many2one字段
1
2
domain=['|', ('instructor', '=', True),
('category_id.name', 'ilike', "Teacher")])
  • _compute_seats报名与座位的比例,xmlfiels需要加widget=”progressbar”
1
2
3
4
5
6
7
@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

  • 默认值default是在modelsfield中来定义
1
2
3
name = fields.Char(default="Unknown")
user_id = fields.Many2one('res.users', default=lambda self: self.env.user)
start_date = fields.Date(default=fields.Date.today)
  • activeodoo中的内置规则,可能是显示的tree视图中,或者根本不显示
1
active = fields.Boolean(default=True)
  • onchange乘积,比如商品数量和价格的关系,或者数据小于某个阀值的时候弹出警告`@api.onchange`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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",
},
}
1
2
3
4
5
6
模型限制
@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")
1
2
3
4
5
6
7
8
9
10
# 在数据库中限制
_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"),
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 拷贝的时候限制
@api.multi
def copy(self, default=None):
default = dict(default or {})

copied_count = self.search_count(
[('name', '=like', u"Copy of {}%".format(self.name))])
if not copied_count:
new_name = u"Copy of {}".format(self.name)
else:
new_name = u"Copy of {} ({})".format(self.name, copied_count)

default['name'] = new_name
return super(Course, self).copy(default)

高级视图

  • 显示的时候不同的值显示不同的颜色
1
2
3
4
<!-- 在这里的比较符号要用 html 的 小于5 天的,或者大于 15 天的-->
<tree string="Session Tree" decoration-info="duration&lt;5" decoration-danger="duration&gt;15">
<!-- 该字段不形式在 tree 视图中 -->
<field name="duration" invisible="1"/>

日历视图

docs

1
2
3
4
5
6
7
<!-- calendar view-->
<!-- color 不同的值颜色不一样 -->
<!-- date_start 日历中的开始时间 -->
<!-- end_date 结束时间 -->
<calendar string="Ideas" date_start="invent_date" color="inventor_id">
<field name="name"/>
</calendar>

搜索视图

docs

1
2
3
4
5
6
7
8
9
<!-- filter_domain 字段 -->
<field name="description" string="Name or description"
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>

<!-- filter 标签 -->
<!-- domain 添加过滤条件 -->
<filter name="my_courses" string="My Courses" domain="[('responsible_id', '=', uid)]"/>
<!-- context 添加分组条件 要在 group 标签中-->
<filter name="by_responsible" string="Responsible" context="{'group_by': 'responsible_id'}"/>

ps: Pycharm find in path 可以很方便的查找

筛选器
分组

甘特图

docs

1
2
3
4
5
<gantt string="Session Gantt"
date_start="start_date" date_delay="hours"
default_group_by='instructor_id'>
<!-- <field name="name"/> this is not required after Odoo 10.0 -->
</gantt>

ps: xml 某些配置在删掉的时候还是会在数据库中的,还是会报错,要给个空值给覆盖掉或者直接去数据库中删除

图表视图

docs

1
2
3
# 如果是计算字段必须加 store=True
attendees_count = fields.Integer(
string="Attendees count", compute='_get_attendees_count', store=True)

看板视图

docs

展开
收拢

改写视图

1
2
3
4
5
6
7
<!--# 直接重写-->
<field name='inherit_id' ref='需要改写的 view'>
<!--# 在后面添加-->
<xpath expr="field[@name='目标ID'" position="after">
<field name="idea_ids" string="Number of ideas">
</xpath>
<!-- 还有替换、修改属性值、请看官网 View inheritance-->