#### 高级视图
[TOC]
##### 树视图
树视图可以采用辅助属性来进一步自定义其行为:
`decoration-{$name}`
允许根据对应记录属性修改行的文本风格。对于每个记录,将使用记录的属性作为上下文来计算表达式,如果值为`true`,则将相应的样式应用于行。其他上下文值为`uid`(当前用户的标识)和`current_date`(`yyyy-MM-dd`格式的当前日期字符串)。`{$name}`可以是`bf(font-weight:bold)`、`it(font-style:italic)`或任何bootstrap上下文颜色(`danger,info,muted,primary,success,warning`)
~~~
<tree string="Idea Categories" decoration-info="state=='draft'"
decoration-danger="state=='trashed'">
<field name="name"/>
<field name="state"/>
</tree>
~~~
`editable`
`top`和`bottom`使树视图可直接编辑(而不需要通过表单视图),其值就是新行出现的位置。
> 练习列表着色
> 编辑授课的树视图,使得持续时间少于5天的授课以蓝色显示,持续时间超过15天的授课以红色显示。编辑授课的树视图:
`openacademy/views/openacademy.xml`
~~~
<field name="name">session.tree</field>
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
<tree string="Session Tree" decoration-info="duration<5" decoration-danger="duration>15">
<field name="name"/>
<field name="course_id"/>
<field name="duration" invisible="1"/>
<field name="taken_seats" widget="progressbar"/>
</tree>
</field>
~~~
##### 日历
将记录显示为日历活动,通过将根元素设置为`<calendar>`,主要的属性有:
`color`
字段的名称通过颜色来区分。颜色会自动分配给事件,但相同颜色定义的事件(`@color`属性有相同值的记录)将被使用相同的颜色。
`date_start`
记录中用于保存事件开始日期/时间的字段。
`date_stop`(可选)
记录中用于保存时间结束日期/时间的字段。
为每个日历事件定义标签的字段
~~~
<calendar string="Ideas" date_start="invent_date" color="inventor_id">
<field name="name"/>
</calendar>
~~~
> 练习日历视图
> 给授课模型添加一个日历视图,使用户可以查看与开放学院相关联的事件。
>
> * 添加一个计算字段`end_date`,通过`start_date`和`duration`计算获得。
> * 反函数使字段可写,并允许在日历视图中移动授课(通过拖放操作)
> * 向授课模型添加日历视图
> * 添加日历视图到授课模型的动作中
`openacademy/models.py`
~~~
# -*- coding: utf-8 -*-
from datetime import timedelta
from odoo import models, fields, api, exceptions
class Course(models.Model):
~~~
~~~
attendee_ids = fields.Many2many('res.partner', string="Attendees")
taken_seats = fields.Float(string="Taken seats", compute='_taken_seats')
end_date = fields.Date(string="End Date", store=True,
compute='_get_end_date', inverse='_set_end_date')
@api.depends('seats', 'attendee_ids')
def _taken_seats(self):
~~~
~~~
},
}
@api.depends('start_date', 'duration')
def _get_end_date(self):
for r in self:
if not (r.start_date and r.duration):
r.end_date = r.start_date
continue
# Add duration to start_date, but: Monday + 5 days = Saturday, so
# subtract one second to get on Friday instead
start = fields.Datetime.from_string(r.start_date)
duration = timedelta(days=r.duration, seconds=-1)
r.end_date = start + duration
def _set_end_date(self):
for r in self:
if not (r.start_date and r.end_date):
continue
# Compute the difference between dates, but: Friday - Monday = 4 days,
# so add one day to get 5 days instead
start_date = fields.Datetime.from_string(r.start_date)
end_date = fields.Datetime.from_string(r.end_date)
r.duration = (end_date - start_date).days + 1
@api.constrains('instructor_id', 'attendee_ids')
def _check_instructor_not_in_attendees(self):
for r in self:
~~~
`openacademy/views/openacademy.xml`
~~~
</field>
</record>
<!-- calendar view -->
<record model="ir.ui.view" id="session_calendar_view">
<field name="name">session.calendar</field>
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
<calendar string="Session Calendar" date_start="start_date"
date_stop="end_date"
color="instructor_id">
<field name="name"/>
</calendar>
</field>
</record>
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar</field>
</record>
<menuitem id="session_menu" name="Sessions"
~~~
##### 搜索视图
搜索视图的`<field>`元素可以使用`@filter_domain`覆盖为在给定字段上搜索而生成的域。在给定的域中,`self`表示用户输入的值。在下面的示例中,它用于搜索两个字段`name`和`description`。搜索视图还可以包含`<filter>`元素,这些元素用作预定义搜索的切换。过滤器必须具有以下属性之一:
`domain`
给搜索指定domain表达式
`context`
给搜索指定上下文;使用`group_by`对结果进行分组。
~~~
<search string="Ideas">
<field name="name"/>
<field name="description" string="Name and description"
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>
<field name="inventor_id"/>
<field name="country_id" widget="selection"/>
<filter name="my_ideas" string="My Ideas"
domain="[('inventor_id', '=', uid)]"/>
<group string="Group By">
<filter name="group_by_inventor" string="Inventor"
context="{'group_by': 'inventor_id'}"/>
</group>
</search>
~~~
对于非默认的搜索视图,使用`search_view_id`字段。而通过`context`字段为搜索字段设置默认值:`search_default_field_name`表单的上下文关键字将初始化field_name的值。搜索过滤器必须有`@name`选项,并且其值是布尔类型的(只能在默认情况可用)
> 练习搜索视图
>
> * 在课程搜索视图中添加按钮,用以筛选当前用户负责的课程,并且作为默认选择。
> * 再添加一个分组按钮,用于对当前用户负责的课程进行分组。
`openacademy/views/openacademy.xml`
~~~
<search>
<field name="name"/>
<field name="description"/>
<filter name="my_courses" string="My Courses"
domain="[('responsible_id', '=', uid)]"/>
<group string="Group By">
<filter name="by_responsible" string="Responsible"
context="{'group_by': 'responsible_id'}"/>
</group>
</search>
</field>
</record>
~~~
~~~
<field name="res_model">openacademy.course</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context" eval="{'search_default_my_courses': 1}"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">Create the first course
</p>
~~~
##### 甘特图
水平条状的甘特图通常用于显示项目计划和进度,根元素是`<gantt>`。
~~~
<gantt string="Ideas"
date_start="invent_date"
date_stop="date_finished"
progress="progress"
default_group_by="inventor_id" />
~~~
> 练习甘特图
> 添加甘特图使用户可以查看授课的日程排期,授课将按讲师分组。
>
> * 创建一个计算字段,表示以小时计算的授课持续时间
> * 添加甘特图,并且将甘特图添加到授课模型的action上。
`openacademy/models.py`
~~~
end_date = fields.Date(string="End Date", store=True,
compute='_get_end_date', inverse='_set_end_date')
hours = fields.Float(string="Duration in hours",
compute='_get_hours', inverse='_set_hours')
@api.depends('seats', 'attendee_ids')
def _taken_seats(self):
for r in self:
~~~
~~~
end_date = fields.Datetime.from_string(r.end_date)
r.duration = (end_date - start_date).days + 1
@api.depends('duration')
def _get_hours(self):
for r in self:
r.hours = r.duration * 24
def _set_hours(self):
for r in self:
r.duration = r.hours / 24
@api.constrains('instructor_id', 'attendee_ids')
def _check_instructor_not_in_attendees(self):
for r in self:
~~~
`openacademy/views/openacademy.xml`
~~~
</field>
</record>
<record model="ir.ui.view" id="session_gantt_view">
<field name="name">session.gantt</field>
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
<gantt string="Session Gantt" color="course_id"
date_start="start_date" date_delay="hours"
default_group_by='instructor_id'>
<field name="name"/>
</gantt>
</field>
</record>
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,gantt</field>
</record>
<menuitem id="session_menu" name="Sessions"
~~~
##### 图形视图
图形视图用来表示对模型的概述和分析,根元素是`<graph>`。
> 注意
> 多维表的核心视图(根元素`<pivot>`)允许选择文件管理器以获得正确的图形数据库,然后再转到更多的图形视图。核心视图与图形视图共享相同的内容定义。
聚合视图有4种显示模式,通过`@type`属性定义。
**Bar(默认值)**
条形图,第一个维度用于在水平轴上定义组,其它维度定义每个组的聚合条。默认情况下,条是并排的,也可以通过`<graph>`的`@stacked="True"`来让条堆叠。
**Line**
2维折线图
**Pie**
2维饼图
图形视图包含的`<field>`元素有`@type`属性定义值:
`row(默认值)`
该字段是聚合的
`measure`
该字段是分组后聚合的
~~~
<graph string="Total idea score by Inventor">
<field name="inventor_id"/>
<field name="score" type="measure"/>
</graph>
~~~
> 警告
> 图形视图只能对数据库字段进行聚合,不能对不存储在数据库的计算字段进行聚合。
>
> 练习图形视图
> 在授课对象中添加图形视图,为每个课程在条形视图下显示出席人数。
>
> * 添加字段将出席人数这计算字段存储在数据库
> * 添加相关图形视图
`openacademy/models.py`
~~~
hours = fields.Float(string="Duration in hours",
compute='_get_hours', inverse='_set_hours')
attendees_count = fields.Integer(
string="Attendees count", compute='_get_attendees_count', store=True)
@api.depends('seats', 'attendee_ids')
def _taken_seats(self):
for r in self:
~~~
~~~
for r in self:
r.duration = r.hours / 24
@api.depends('attendee_ids')
def _get_attendees_count(self):
for r in self:
r.attendees_count = len(r.attendee_ids)
@api.constrains('instructor_id', 'attendee_ids')
def _check_instructor_not_in_attendees(self):
for r in self:
~~~
`openacademy/views/openacademy.xml`
~~~
</field>
</record>
<record model="ir.ui.view" id="openacademy_session_graph_view">
<field name="name">openacademy.session.graph</field>
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
<graph string="Participations by Courses">
<field name="course_id"/>
<field name="attendees_count" type="measure"/>
</graph>
</field>
</record>
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,gantt,graph</field>
</record>
<menuitem id="session_menu" name="Sessions"
~~~
##### 看板视图
看板视图用于任务组织、生产进度等,根元素是`<kanban>`。看板视图显示一组可按列分组的卡片。每个卡片表示一个记录,每列都显示聚合字段的值。例如项目任务可以按阶段(每列是一个阶段)分组或者按负责人(每列是一个用户)分组。看板视图将每个卡的结构定义为表单元素(包括基本HTML)和QWeb的混合。
> 练习看板视图
> 添加显示按课程分组的授课看板视图(列是课程)
>
> * 授课模型中添加整型字段`color`
> * 添加看板视图并更新action
`openacademy/models.py`
~~~
duration = fields.Float(digits=(6, 2), help="Duration in days")
seats = fields.Integer(string="Number of seats")
active = fields.Boolean(default=True)
color = fields.Integer()
instructor_id = fields.Many2one('res.partner', string="Instructor",
domain=['|', ('instructor', '=', True),
~~~
`openacademy/views/openacademy.xml`
~~~
</record>
<record model="ir.ui.view" id="view_openacad_session_kanban">
<field name="name">openacad.session.kanban</field>
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
<kanban default_group_by="course_id">
<field name="color"/>
<templates>
<t t-name="kanban-box">
<div
t-attf-class="oe_kanban_color_{{kanban_getcolor(record.color.raw_value)}}
oe_kanban_global_click_edit oe_semantic_html_override
oe_kanban_card {{record.group_fancy==1 ? 'oe_kanban_card_fancy' : ''}}">
<div class="oe_dropdown_kanban">
<!-- dropdown menu -->
<div class="oe_dropdown_toggle">
<i class="fa fa-bars fa-lg"/>
<ul class="oe_dropdown_menu">
<li>
<a type="delete">Delete</a>
</li>
<li>
<ul class="oe_kanban_colorpicker"
data-field="color"/>
</li>
</ul>
</div>
<div class="oe_clear"></div>
</div>
<div t-attf-class="oe_kanban_content">
<!-- title -->
Session name:
<field name="name"/>
<br/>
Start date:
<field name="start_date"/>
<br/>
duration:
<field name="duration"/>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,gantt,graph,kanban</field>
</record>
<menuitem id="session_menu" name="Sessions"
parent="openacademy_menu"
~~~
作者:luohuayong
链接:http://www.jianshu.com/p/511f32b28a13
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 开发教程
- Odoo10开发教程一(构建模块)
- Odoo10开发教程二(基本视图)
- Odoo10开发教程三(模型关联)
- Odoo10开发教程四(继承)
- Odoo10开发教程五(计算字段和默认值)
- Odoo10开发教程六(高级视图)
- Odoo10开发教程七(工作流和安全)
- 参考手册
- odoo V10中文参考手册(一:ORM API)
- odoo V10中文参考手册(指导规范)
- 技巧
- odoo 常用widget
- Odoo(OpenERP)开发实践:菜单隐藏(1)
- Odoo(OpenERP)开发实践:菜单隐藏(2)
- Odoo(OpenERP)开发实践:数据模型学习
- Odoo中自动备份数据库
- Odoo(OpenERP)应用实践: 使用db-filter参数实现通过域名指定访问哪个数据库
- Odoo(OpenERP)配置文件openerp-server.conf详解
- Odoo(OpenERP v8)数据模型(Data Model)
- odoo10学习笔记十七:controller
- Qweb定义