Basic Views
Views 定義了 model 中的 record 的展現方式,每種類型的 view 都代提供了 model 的一種數據可視化(list 展現, 圖表的方式展現,等), views 可以通過他們的 type (e.g. a list of partners)或者明確指定它的 external id 來被請求。對於一般的請求來說,the view with 正確的 type 和 最低優先級的 將被調用(所以, the lowest-priority view of each type 就是 默認view of each type)
view 的繼承機制,使得我們可以在任意地方對該view進行添加或者刪除其中的元素。
Generic view declaration
A View 就被聲明爲一個record,不過這個record的 model 是 ir.ui.view。 view type 將在 record 的 arch field 中設置
<record model="ir.ui.view" id="view_id">
<field name="name">view.name</field>
<field name="model">object_name</field>
<field name="priority" eval="16"/>
<field name="arch" type="xml">
<!-- view content: <form>, <tree>, <graph>, ... -->
</field>
</record>
Tree views
Tree views 通常也被稱爲 list views,以表格的方式展現所有 records
root element 是 <tree>
,最普遍的就是將model的所有字段展現出來,每個 field 就是一個 column
<tree string="Idea list">
<field name="name"/>
<field name="inventor_id"/>
</tree>
Form Views
Forms 是用來新建和修改 單一 record
root element 是 <form>
,它集成了 高度結構化的 elements (groups, notebook) 還有交互式的 element(buttons and fields):
<form string="Idea form">
<group colspan="4">
<group colspan="2" col="2">
<separator string="General stuff" colspan="2"/>
<field name="name"/>
<field name="inventor_id"/>
</group>
<group colspan="2" col="2">
<separator string="Dates" colspan="2"/>
<field name="active"/>
<field name="invent_date" readonly="1"/>
</group>
<notebook colspan="4">
<page string="Description">
<field name="description" nolabel="1"/>
</page>
</notebook>
<field name="state"/>
</group>
</form>
練習 2-1
通過XML 爲Course object 設置 from view
openacademy/views/openacademy.xml
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<!-- 新增 -->
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="arch" type="xml">
<form string="Course Form">
<sheet>
<group>
<field name="name"/>
</group>
<notebook>
<page string="Description">
<field name="description"/>
</page>
<page string="About">
This is an example of notebooks
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- 結束 -->
<!-- window action -->
<!--
The following tag is an action definition for a "window action",
Form views 也可以使用普通的HTML
<form string="Idea Form">
<header>
<button string="Confirm" type="object" name="action_confirm"
states="draft" class="oe_highlight" />
<button string="Mark as done" type="object" name="action_done"
states="confirmed" class="oe_highlight"/>
<button string="Reset to draft" type="object" name="action_draft"
states="confirmed,done" />
<field name="state" widget="statusbar"/>
</header>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only" string="Idea Name" />
<h1><field name="name" /></h1>
</div>
<separator string="General" colspan="2" />
<group colspan="2" col="2">
<field name="description" placeholder="Idea description..." />
</group>
</sheet>
</form>
Search views
Search views 定製了 search field 用以在 list view 或者 其它aggregated views 中進行篩選。root element 就是 <search>
,在這其中就包含了,哪些 field 是可以被 search 的
<search>
<field name="name"/>
<field name="inventor_id"/>
</search>
如果沒有設置 search view,那麼Odoo將自動生成一個 search view,但是隻包含model中 name 字段。這也是爲什麼上一章講到 name 是 特殊字段。
練習 2-2
爲course 添加 search view,可以通過 title 或者 description 搜索到
openacademy/views/openacademy.xml
</field>
</record>
<!-- 新增 -->
<record model="ir.ui.view" id="course_search_view">
<field name="name">course.search</field>
<field name="model">openacademy.course</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<field name="description"/>
</search>
</field>
</record>
<!-- 結束 -->
<!-- window action -->
<!--
The following tag is an action definition for a "window action",
Relations between models
一個 model 的 record 可能會關聯到另一個 model 的 record。比如,一個銷售訂單 record 會包含客戶 record,在客戶record中含有客戶的相關數據;而且,銷售訂單record 裏面通常還有 sale order line records.
練習 2-3
創建一個 會議 model , session model
在 module Open Acadmy中,我們希望的 session model 是 在 course 的基礎上,在某時間段,有一定的參與人數的會議。
對 session 創建一個model, 包括 name, start date, duration and a number of seats。再添加 action 和 menu 用以展現 sessions,
- 創建 class Session in openacademy/models.py
- 添加 access to the session object in openacademy/view/openacademy.xml
openacademy/models.py
name = fields.Char(string="Title", required=True)
description = fields.Text()
class Session(models.Model):
_name = 'openacademy.session'
name = fields.Char(required=True)
start_date = fields.Date()
# 6代表浮點數的total number, 2代表有兩位小數
duration = fields.Float(digits=(6, 2), help="Duration in days")
seats = fields.Integer(string="Number of seats")
openacademy/views/openacademy.xml
<!-- Full id location:
action="openacademy.course_list_action"
It is not required when it is the same module -->
<!-- 新增 -->
<!-- session form view -->
<record model="ir.ui.view" id="session_form_view">
<field name="name">session.form</field>
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
<form string="Session Form">
<sheet>
<group>
<field name="name"/>
<field name="start_date"/>
<field name="duration"/>
<field name="seats"/>
</group>
</sheet>
</form>
</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</field>
</record>
<menuitem id="session_menu" name="Sessions"
parent="openacademy_menu"
action="session_list_action"/>
<!-- 結束 -->
</data>
</openerp>
Relational fields
Relational fields 將同一 model 的records 連接起來(通常表示層級的關係),或者不同model的 records連接起來。
field types 有:
- Many2one(other_model, ondelete=’set null’)
使用方式爲
print foo.other_id.name
- One2many(other_model, related_field)
一種虛擬的關係,和Many2one相反,一個 One2many 通常包含多個records,所以需要使用loop語句
for other in foo.other_ids:
print other.name
由於 One2many 是虛擬關係,所以必須有一個 other_model,而且 other_model 中必須有一個 Many2one field,且 field name 必須爲 related_field
- Many2many(other_model)
雙向多對多的關係,任意方的 record 都可以link 到 對面的 多個 records
for other in foo.other_ids:
print other.name
練習 2-4
使用 many2one,使 model Course and Session 相互關聯起來
- A course 應該有一個負責人 responsible user, 這個field 應該關聯到一個 Odoo 的內建 model : res.users
- A session 有一個教員 instructor, 關聯到內建model : res.partner
- A session 關聯到 a course ,就是 model: openacademy.course, 並且設置 required=True
- 修改 Views
openacademy/models.py
name = fields.Char(string="Title", required=True)
description = fields.Text()
# 新增
responsible_id = fields.Many2one('res.users',
ondelete='set null', string="Responsible", index=True)
# 結束
class Session(models.Model):
_name = 'openacademy.session'
start_date = fields.Date()
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")
course_id = fields.Many2one('openacademy.course',
ondelete='cascade', string="Course", required=True)
# 結束
openacademy/views/openacademy.xml
<sheet>
<group>
<field name="name"/>
<!-- 新增 -->
<field name="responsible_id"/>
<!-- 結束 -->
</group>
<notebook>
<page string="Description">
</field>
</record>
<!-- 新增 -->
<!-- override the automatically generated list view for courses -->
<record model="ir.ui.view" id="course_tree_view">
<field name="name">course.tree</field>
<field name="model">openacademy.course</field>
<field name="arch" type="xml">
<tree string="Course Tree">
<field name="name"/>
<field name="responsible_id"/>
</tree>
</field>
</record>
<!-- 結束 -->
<!-- window action -->
<!--
The following tag is an action definition for a "window action",
<form string="Session Form">
<sheet>
<group>
<!-- 新增 -->
<group string="General">
<field name="course_id"/>
<field name="name"/>
<field name="instructor_id"/>
</group>
<group string="Schedule">
<field name="start_date"/>
<field name="duration"/>
<field name="seats"/>
</group>
<!-- 結束 -->
</group>
</sheet>
</form>
</field>
</record>
<!-- 新增 -->
<!-- session tree/list view -->
<record model="ir.ui.view" id="session_tree_view">
<field name="name">session.tree</field>
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
<tree string="Session Tree">
<field name="name"/>
<field name="course_id"/>
</tree>
</field>
</record>
<!-- 結束 -->
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
練習 2-5
通過使用 one2many field, 修改模型以反映course和session之間的關係。
openacademy/models.py
responsible_id = fields.Many2one('res.users',
# 新增
ondelete='set null', string="Responsible", index=True)
session_ids = fields.One2many(
'openacademy.session', 'course_id', string="Sessions")
# 結束
class Session(models.Model):
openacademy/views/openacademy.xml
<page string="Description">
<field name="description"/>
</page>
<!-- 新增 -->
<page string="Sessions">
<field name="session_ids">
<tree string="Registered sessions">
<field name="name"/>
<field name="instructor_id"/>
</tree>
</field>
</page>
<!-- 結束 -->
</notebook>
</sheet>
練習 2-6
通過使用many2many field, 修改 session model 使其 每個session 都與一定數目的 attendees,attendees 來自 內建model res.parter
openacademy/models.py
instructor_id = fields.Many2one('res.partner', string="Instructor")
course_id = fields.Many2one('openacademy.course',
ondelete='cascade', string="Course", required=True)
# 新增
attendee_ids = fields.Many2many('res.partner', string="Attendees")
# 結束
openacademy/views/openacademy.xml
<field name="seats"/>
</group>
</group>
<!-- 新增 -->
<label for="attendee_ids"/>
<field name="attendee_ids"/>
<!-- 結束 -->
</sheet>
</form>
</field>