Odoo功能的開發與編程的演化極快,從Odoo 11版到12版,再到發布此學習筆記時的13版,已有許多程式邏輯不再適用,此外學習資源也十分混亂與零散,社群版與企業版的差異更是讓開發者必須額外改寫系統的繼承對象,如果開發者是獨自工作,少有支持社群的交流與配合,根本難以發展這套系統。
此書非常不容易閱讀,加上書上部分內容甚至是直接複製官方出版的開發手冊,因此看不懂的地方還是無法讓人看懂,甚至本書作者在GitHub的模組範例,在本書支持的12版,連安裝都無法安裝,debug過程是相當沒有頭緒的,有鑑於職涯規劃與個人考量,短期的未來將不再鑽研這套Odoo系統。
網頁和控制器
l 在controllers資料夾內創建openacademy_controllers.py:
# -*- coding: utf-8 -*-
# Author: Timmy Nueh
from odoo import http
class Girl(http.Controller):
# 使用裝飾器綁定路由
@http.route('/openacademy')
def GirlManage(self, **kwargs):
girls = http.request.env['openacademy.student']
domain_girl = [('student_fm', '=', 'F')]
girls_open = girls.search(domain_girl)
# 由HTML顯示字串的方式為return ('<h1>Hello World!</h1>')
# 一般採用QWeb模板的方式來製作頁面,因為直接使用HTML不夠靈活,效率也不高
return http.request.render('openacademy.openacademy_girls_template', {'girls_open': girls_open})
# auth='public'代表不需要登入就可以檢視,website=True代表使用網頁
@http.route('/hello', auth='public', website=True)
def hello(self, **kwargs):
return http.request.render('openacademy.hello')
# -*- coding: utf-8 -*-
# Author: Timmy Nueh
from odoo import http
class Girl(http.Controller):
# 使用裝飾器綁定路由
@http.route('/openacademy')
def GirlManage(self, **kwargs):
girls = http.request.env['openacademy.student']
domain_girl = [('student_fm', '=', 'F')]
girls_open = girls.search(domain_girl)
# 由HTML顯示字串的方式為return ('<h1>Hello World!</h1>')
# 一般採用QWeb模板的方式來製作頁面,因為直接使用HTML不夠靈活,效率也不高
return http.request.render('openacademy.openacademy_girls_template', {'girls_open': girls_open})
# auth='public'代表不需要登入就可以檢視,website=True代表使用網頁
@http.route('/hello', auth='public', website=True)
def hello(self, **kwargs):
return http.request.render('openacademy.hello')
l 在controllers資料夾內創建openacademy_girls_template.xml:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="openacademy_girls_template" name="girls">
<div class="container">
<h1>girls_option</h1>
<t t-foreach="girls_open" t-as="girl">
<div class="row">
<span t-field="girl.student_no"/>
<span t-field="girl.student_name"/>
<span t-field="girl.student_contact"/>
<span t-field="girl.student_class"/>
<span t-field="girl.student_fm"/>
</div>
</t>
</div>
</template>
<template id="hello" name="Hello World">
<t t-call="website.layout">
<h1>Hello World!</h1>
</t>
</template>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="openacademy_girls_template" name="girls">
<div class="container">
<h1>girls_option</h1>
<t t-foreach="girls_open" t-as="girl">
<div class="row">
<span t-field="girl.student_no"/>
<span t-field="girl.student_name"/>
<span t-field="girl.student_contact"/>
<span t-field="girl.student_class"/>
<span t-field="girl.student_fm"/>
</div>
</t>
</div>
</template>
<template id="hello" name="Hello World">
<t t-call="website.layout">
<h1>Hello World!</h1>
</t>
</template>
</data>
</odoo>
l 修改__manifest__.py:
# 原程式碼增加以下程式碼
'depends': ['website'],
# 原程式碼增加以下程式碼
'depends': ['website'],
l 設置__init__.py與__manifest__.py等檔案之後Upgrade Module,瀏覽http://localhost:8069/openacademy:
l 瀏覽http://localhost:8069/hello:
網頁和控制器繼承
l 在controllers資料夾內創建openacademy_controllers_extend.py:
# -*- coding: utf-8 -*-
# Author: Timmy Nueh
from odoo import http
from custom.openacademy.controllers.openacademy_controllers import Girl
class GirlExtend(Girl):
@http.route('/openacademy/<name>')
def GirlContact(self, name=None, **kwargs):
response = super(GirlExtend, self).GirlManage()
response.qcontext['name'] = name
return response
# -*- coding: utf-8 -*-
# Author: Timmy Nueh
from odoo import http
from custom.openacademy.controllers.openacademy_controllers import Girl
class GirlExtend(Girl):
@http.route('/openacademy/<name>')
def GirlContact(self, name=None, **kwargs):
response = super(GirlExtend, self).GirlManage()
response.qcontext['name'] = name
return response
l
在controllers資料夾內創建openacademy_girls_template_extend.xml:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="openacademy_girls_template_extend"
name="girls_extend"
inherit_id="openacademy.openacademy_girls_template">
<xpath expr="//h1" position="before">
<h1>
Hello <t t-esc="name or 'Someone'" />!
</h1>
</xpath>
</template>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="openacademy_girls_template_extend"
name="girls_extend"
inherit_id="openacademy.openacademy_girls_template">
<xpath expr="//h1" position="before">
<h1>
Hello <t t-esc="name or 'Someone'" />!
</h1>
</xpath>
</template>
</data>
</odoo>
l 設置__init__.py與__manifest__.py等檔案之後Upgrade Module,瀏覽http://localhost:8069/openacademy:
l 瀏覽時傳遞參數:
@http.route(['/openacademy', '/openacademy/<name>'])
如同上例,直接輸入http://localhost:8069/openacademy/Timmy瀏覽
@http.route('/openacademy/<int:user_id>')
會將user_id參數提取為整數值
@http.route('/openacademy/<model("res.users"):user>')
會將user參數提取為res.users模型的紀錄對象
@http.route(['/openacademy', '/openacademy/<name>'])
如同上例,直接輸入http://localhost:8069/openacademy/Timmy瀏覽
@http.route('/openacademy/<int:user_id>')
會將user_id參數提取為整數值
@http.route('/openacademy/<model("res.users"):user>')
會將user參數提取為res.users模型的紀錄對象
層級結構關係
l 在models資料夾內創建openacademy_hierarchy.py:
# -*- coding: utf-8 -*-
# Author: Timmy Nueh
from odoo import models, fields, api
class Hierarchy(models.Model):
_name = 'openacademy.hierarchy'
_description = '層級範例'
# 層級結構關係使用_parent_store模型屬性,提高讀取數據的效率,但是損害寫入數據的效率
_parent_store = True
_parent_name = 'parent_id'
name = fields.Char('名稱')
parent_id = fields.Many2one('openacademy.hierarchy', '父標示', ondelete='restrict')
parent_path = fields.Char(index=True)
# -*- coding: utf-8 -*-
# Author: Timmy Nueh
from odoo import models, fields, api
class Hierarchy(models.Model):
_name = 'openacademy.hierarchy'
_description = '層級範例'
# 層級結構關係使用_parent_store模型屬性,提高讀取數據的效率,但是損害寫入數據的效率
_parent_store = True
_parent_name = 'parent_id'
name = fields.Char('名稱')
parent_id = fields.Many2one('openacademy.hierarchy', '父標示', ondelete='restrict')
parent_path = fields.Char(index=True)
l 在views資料夾內創建openacademy_hierarchy.xml:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_openacademy_hierarchy_tree" model="ir.ui.view">
<field name="name">view.openacademy.hierarchy.tree</field>
<field name="model">openacademy.hierarchy</field>
<field name="arch" type="xml">
<tree string="">
<field name="name"/>
<field name="parent_id"/>
</tree>
</field>
</record>
<record id="view_openacademy_hierarchy_form" model="ir.ui.view">
<field name="name">view.openacademy.hierarchy.form</field>
<field name="model">openacademy.hierarchy</field>
<field name="arch" type="xml">
<form string="">
<sheet>
<group>
<field name="name"/>
<field name="parent_id"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_openacademy_hierarchy_view" model="ir.actions.act_window">
<field name="name">層級範例資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.hierarchy</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_openacademy_hierarchy_tree" model="ir.ui.view">
<field name="name">view.openacademy.hierarchy.tree</field>
<field name="model">openacademy.hierarchy</field>
<field name="arch" type="xml">
<tree string="">
<field name="name"/>
<field name="parent_id"/>
</tree>
</field>
</record>
<record id="view_openacademy_hierarchy_form" model="ir.ui.view">
<field name="name">view.openacademy.hierarchy.form</field>
<field name="model">openacademy.hierarchy</field>
<field name="arch" type="xml">
<form string="">
<sheet>
<group>
<field name="name"/>
<field name="parent_id"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_openacademy_hierarchy_view" model="ir.actions.act_window">
<field name="name">層級範例資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.hierarchy</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
</data>
</odoo>
l 設置__init__.py、__manifest__.py、openacademy_menu.xml、ir.model.access.csv等檔案之後Upgrade Module:
引用字段的動態關係
l 承襲上例,在models資料夾內修改openacademy_hierarchy.py:
# 原程式碼增加以下程式碼
dynamic_user = fields.Reference([('res.users', '用戶'), ('res.partner', '合作伙伴')], '使用者')
# 原程式碼增加以下程式碼
dynamic_user = fields.Reference([('res.users', '用戶'), ('res.partner', '合作伙伴')], '使用者')
l 設置openacademy_hierarchy.xml等檔案之後Upgrade Module:
通信API
l 在__manifest__.py增加以下程式碼:
'depends': ['mail']
'depends': ['mail']
l 承襲前一系列學習筆記範例,在models資料夾內修改openacademy_student.py:
# 抽象模型沒有對應的資料表,不能被直接使用,而是做為混合類別來使用;它提供了現成的功能模板,用的時候需繼承使用
_inherit = ['mail.thread']
# 若要追蹤特定欄位值的變更,增加紫色粗體字的部分
student_contact = fields.Char(string='聯絡人', track_visibility='onchange')
# 抽象模型沒有對應的資料表,不能被直接使用,而是做為混合類別來使用;它提供了現成的功能模板,用的時候需繼承使用
_inherit = ['mail.thread']
# 若要追蹤特定欄位值的變更,增加紫色粗體字的部分
student_contact = fields.Char(string='聯絡人', track_visibility='onchange')
l 在views資料夾內的openacademy_student.xml增加紫色粗體字的部分:
<form string="">
<sheet>
<group>
<field name="student_no"/>
<field name="student_name"/>
<field name="student_contact"/>
<field name="student_class"/>
<field name="student_birthday"/>
<field name="student_fm"/>
<field name="student_memo"/>
<field name="student_obj"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
<form string="">
<sheet>
<group>
<field name="student_no"/>
<field name="student_name"/>
<field name="student_contact"/>
<field name="student_class"/>
<field name="student_birthday"/>
<field name="student_fm"/>
<field name="student_memo"/>
<field name="student_obj"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
l Upgrade Module:
不可任意異動Many2one字段關聯的資料表
l 承襲前一系列學習筆記範例,在views資料夾內的openacademy_score.xml增加紫色粗體字的部分:
<form string="">
<sheet>
<group>
<field name="score_year"/>
<!--score_student為Many2one字段物件-->
<field name="score_student" options="{'no_create': True, 'no_create_edit': True}"/>
<field name="score_chinese"/>
<field name="score_math"/>
<field name="score_english"/>
<field name="score_total"/>
<field name="score_avg"/>
<field name="score_bank"/>
</group>
</sheet>
</form>
<form string="">
<sheet>
<group>
<field name="score_year"/>
<!--score_student為Many2one字段物件-->
<field name="score_student" options="{'no_create': True, 'no_create_edit': True}"/>
<field name="score_chinese"/>
<field name="score_math"/>
<field name="score_english"/>
<field name="score_total"/>
<field name="score_avg"/>
<field name="score_bank"/>
</group>
</sheet>
</form>
l Upgrade Module,改變前與改變後的比較:
上傳、下載檔案顯示檔名且檔名保持相同
l 承襲上例,在models資料夾內修改openacademy_hierarchy.py:
# 原程式碼增加以下程式碼
powerpoint = fields.Binary(string='PowerPoint')
excel = fields.Binary(string='Excel')
powerpoint_filename = fields.Char(string='PowerPoint Filename')
excel_filename = fields.Char(string='Excel Filename')
# 原程式碼增加以下程式碼
powerpoint = fields.Binary(string='PowerPoint')
excel = fields.Binary(string='Excel')
powerpoint_filename = fields.Char(string='PowerPoint Filename')
excel_filename = fields.Char(string='Excel Filename')
l 在views資料夾內的openacademy_hierarchy.xml增加紫色粗體字的部分:
<form string="">
<sheet>
<group>
<field name="name"/>
<field name="parent_id"/>
<field name="dynamic_user"/>
<field name="powerpoint" widget="binary" filename="powerpoint_filename"/>
<field name="excel" widget="binary" filename="excel_filename"/>
<field name="powerpoint_filename" attrs="{'invisible':1}"/>
<field name="excel_filename" attrs="{'invisible':1}"/>
</group>
</sheet>
</form>
<form string="">
<sheet>
<group>
<field name="name"/>
<field name="parent_id"/>
<field name="dynamic_user"/>
<field name="powerpoint" widget="binary" filename="powerpoint_filename"/>
<field name="excel" widget="binary" filename="excel_filename"/>
<field name="powerpoint_filename" attrs="{'invisible':1}"/>
<field name="excel_filename" attrs="{'invisible':1}"/>
</group>
</sheet>
</form>
l Upgrade Module,改變前與改變後的比較:
本書範例-彈出式視窗的預設內容、按鈕的執行邏輯
l 在models資料夾內瀏覽bug_wizard.py:
from odoo import models, fields, api
import logging
from odoo import exceptions
_logger=logging.getLogger(__name__)
class bugWizard(models.TransientModel):
_name = 'bug.wizard'
bug_ids = fields.Many2many('bm.bug', string='Bug')
new_is_closed = fields.Boolean('是否關閉')
wizard_user_id = fields.Many2one('res.users', string='負責人')
# 彈出式視窗內容預設為勾選的內容
@api.model
def default_get(self, field_names):
defaults = super(bugWizard, self).default_get(field_names)
defaults['bug_ids'] = self.env.context['active_ids']
return defaults
# "批量更新"按鈕的執行邏輯
@api.multi
def update_batch(self):
self.ensure_one()
if not (self.new_is_closed or self.wizard_user_id):
raise exceptions.ValidationError('無數據要更新')
_logger.debug('批量bug更新操作 %s', self.bug_ids.ids)
vals={}
if self.new_is_closed:
vals['is_closed'] = self.new_is_closed
if self.wizard_user_id:
vals['user_id'] = self.wizard_user_id
if vals:
self.bug_ids.write(vals)
return True
# "統計bug數"按鈕的執行邏輯
@api.multi
def count_bugs(self):
bug = self.env['bm.bug']
count = bug.search_count([])
raise exceptions.Warning('有%d條bug'%count)
# 接續"獲取bug"按鈕的執行邏輯
@api.multi
def helper_form(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'res_model': self._name,
'res_id': self.id,
'view_type': 'form',
'view_mode': 'form',
'target': 'new'}
# "獲取bug"按鈕的執行邏輯
@api.multi
def get_bugs(self):
self.ensure_one()
bug = self.env['bm.bug']
all_bugs = bug.search([('is_closed', '=', False)])
self.bug_ids = all_bugs
return self.helper_form()
from odoo import models, fields, api
import logging
from odoo import exceptions
_logger=logging.getLogger(__name__)
class bugWizard(models.TransientModel):
_name = 'bug.wizard'
bug_ids = fields.Many2many('bm.bug', string='Bug')
new_is_closed = fields.Boolean('是否關閉')
wizard_user_id = fields.Many2one('res.users', string='負責人')
# 彈出式視窗內容預設為勾選的內容
@api.model
def default_get(self, field_names):
defaults = super(bugWizard, self).default_get(field_names)
defaults['bug_ids'] = self.env.context['active_ids']
return defaults
# "批量更新"按鈕的執行邏輯
@api.multi
def update_batch(self):
self.ensure_one()
if not (self.new_is_closed or self.wizard_user_id):
raise exceptions.ValidationError('無數據要更新')
_logger.debug('批量bug更新操作 %s', self.bug_ids.ids)
vals={}
if self.new_is_closed:
vals['is_closed'] = self.new_is_closed
if self.wizard_user_id:
vals['user_id'] = self.wizard_user_id
if vals:
self.bug_ids.write(vals)
return True
# "統計bug數"按鈕的執行邏輯
@api.multi
def count_bugs(self):
bug = self.env['bm.bug']
count = bug.search_count([])
raise exceptions.Warning('有%d條bug'%count)
# 接續"獲取bug"按鈕的執行邏輯
@api.multi
def helper_form(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'res_model': self._name,
'res_id': self.id,
'view_type': 'form',
'view_mode': 'form',
'target': 'new'}
# "獲取bug"按鈕的執行邏輯
@api.multi
def get_bugs(self):
self.ensure_one()
bug = self.env['bm.bug']
all_bugs = bug.search([('is_closed', '=', False)])
self.bug_ids = all_bugs
return self.helper_form()
l 在views資料夾內瀏覽bug_wizard.xml:
<odoo>
<data>
<record id="bug_wizard" model="ir.ui.view">
<field name="name">bug管理-嚮導</field>
<field name="model">bug.wizard</field>
<field name="arch" type="xml">
<form>
<!--右上角按鈕-->
<div class="oe_right">
<button type="object" name="count_bugs" string="統計bug數"/>
<button type="object" name="get_bugs" string="獲取bug"/>
</div>
<field name="bug_ids">
<tree>
<field name="name"/>
<field name="user_id"/>
<field name="is_closed"/>
</tree>
</field>
<group>
<group><field name="wizard_user_id"/></group>
<group><field name="new_is_closed"/></group>
</group>
<!--特定條件下顯示按鈕-->
<footer>
<button type="object"
name="update_batch"
string="批量更新"
class="oe_highlight"
attrs="{'invisible':[('new_is_closed','=',False), ('wizard_user_id','=',False)]}"/>
</footer>
</form>
</field>
</record>
<!--act_window有兩種寫法,此種更為簡潔-->
<!--name是指通過本窗口動作打開視圖的標題-->
<!--res_model是窗體動作使用的模型名稱-->
<!--view_mode用於聲明可用的視圖類型及其順序-->
<!--target如果設置為new則將在彈出的對話窗口中打開視圖,預設current在主內容區域中打開新視圖-->
<!--context設置目標視圖的上下文訊息-->
<!--domain可強制對打開的視圖中可瀏覽的紀錄進行過濾-->
<!--limit是列表視圖中每個頁面的紀錄數-->
<!--src_model為通過動作菜單訪問的模型-->
<!--multi用於啟用列表視圖上的操作,處理多個選定的紀錄-->
<act_window id="action_bug_wizard"
name="bug管理嚮導"
src_model="bm.bug"
res_model="bug.wizard"
view_mode="form"
target="new"
multi="True"/>
</data>
</odoo>
<odoo>
<data>
<record id="bug_wizard" model="ir.ui.view">
<field name="name">bug管理-嚮導</field>
<field name="model">bug.wizard</field>
<field name="arch" type="xml">
<form>
<!--右上角按鈕-->
<div class="oe_right">
<button type="object" name="count_bugs" string="統計bug數"/>
<button type="object" name="get_bugs" string="獲取bug"/>
</div>
<field name="bug_ids">
<tree>
<field name="name"/>
<field name="user_id"/>
<field name="is_closed"/>
</tree>
</field>
<group>
<group><field name="wizard_user_id"/></group>
<group><field name="new_is_closed"/></group>
</group>
<!--特定條件下顯示按鈕-->
<footer>
<button type="object"
name="update_batch"
string="批量更新"
class="oe_highlight"
attrs="{'invisible':[('new_is_closed','=',False), ('wizard_user_id','=',False)]}"/>
</footer>
</form>
</field>
</record>
<!--act_window有兩種寫法,此種更為簡潔-->
<!--name是指通過本窗口動作打開視圖的標題-->
<!--res_model是窗體動作使用的模型名稱-->
<!--view_mode用於聲明可用的視圖類型及其順序-->
<!--target如果設置為new則將在彈出的對話窗口中打開視圖,預設current在主內容區域中打開新視圖-->
<!--context設置目標視圖的上下文訊息-->
<!--domain可強制對打開的視圖中可瀏覽的紀錄進行過濾-->
<!--limit是列表視圖中每個頁面的紀錄數-->
<!--src_model為通過動作菜單訪問的模型-->
<!--multi用於啟用列表視圖上的操作,處理多個選定的紀錄-->
<act_window id="action_bug_wizard"
name="bug管理嚮導"
src_model="bm.bug"
res_model="bug.wizard"
view_mode="form"
target="new"
multi="True"/>
</data>
</odoo>
XML視圖字段屬性介紹
l 視圖字段通用屬性:
name-為字段的資料庫欄位名字。
string-為字段的標籤文字。
help-為字段的提示訊息。
placeholder-為輸入訊息之前,在字段內顯示的提示文字。
widget-修改系統為字段預設的展示組件。
options-透過JSON資料結構進行設定,例如關聯字段禁止創建紀錄,options="{'no_open': True, 'no_create': True}"。
class-為字段的CSS。
nolabel="True"-禁止自動添加標籤屬性。
invisible="True"-該字段隱藏。
readonly="True"-該字段唯讀。
required="True"-該字段必填。
name-為字段的資料庫欄位名字。
string-為字段的標籤文字。
help-為字段的提示訊息。
placeholder-為輸入訊息之前,在字段內顯示的提示文字。
widget-修改系統為字段預設的展示組件。
options-透過JSON資料結構進行設定,例如關聯字段禁止創建紀錄,options="{'no_open': True, 'no_create': True}"。
class-為字段的CSS。
nolabel="True"-禁止自動添加標籤屬性。
invisible="True"-該字段隱藏。
readonly="True"-該字段唯讀。
required="True"-該字段必填。
l 按鈕字段才可使用的屬性:
string-為按鈕的文字標籤。
type-要執行的操作類型,object表示使用後台Python方法,action表示要執行一個窗口動作。
name-type若為object,代表模型方法名稱;type若為action,代表要執行的窗口動作資料庫ID。
args-type若為object時使用,用於向後台Python方法傳遞參數。
context-用於設定要傳遞的預設值。
confirm-用於執行相關動作之前,顯示確認訊息框。
special="cancel"-用於在嚮導窗口(勾選資料後執行動作)內增加一個取消按鈕。
icon-用於顯示按鈕中的圖像。
string-為按鈕的文字標籤。
type-要執行的操作類型,object表示使用後台Python方法,action表示要執行一個窗口動作。
name-type若為object,代表模型方法名稱;type若為action,代表要執行的窗口動作資料庫ID。
args-type若為object時使用,用於向後台Python方法傳遞參數。
context-用於設定要傳遞的預設值。
confirm-用於執行相關動作之前,顯示確認訊息框。
special="cancel"-用於在嚮導窗口(勾選資料後執行動作)內增加一個取消按鈕。
icon-用於顯示按鈕中的圖像。
l 看板字段才可使用的屬性:
default_group_by-看板卡片的預設階段列。
default_order-看板項目的預設順序。
quick_create="false"-禁用每階段列上方的創建+號鍵,false小寫是JS的設定。
group_create-可以設定false禁止對應的操作。
group_edit-可以設定false禁止對應的操作。
group_delete-可以設定false禁止對應的操作。
on_create-當使用者點擊左上角的創建按鈕時,設定彈出的窗口,方式是<module>.<XML ID>。
default_group_by-看板卡片的預設階段列。
default_order-看板項目的預設順序。
quick_create="false"-禁用每階段列上方的創建+號鍵,false小寫是JS的設定。
group_create-可以設定false禁止對應的操作。
group_edit-可以設定false禁止對應的操作。
group_delete-可以設定false禁止對應的操作。
on_create-當使用者點擊左上角的創建按鈕時,設定彈出的窗口,方式是<module>.<XML ID>。
l 特定字段才可使用的屬性:
文字類型的字段-password="True"-以密碼的形式顯示,而不是明碼。
二進制類型的字段-filename-儲存文件名稱。
One2many字段-mode-指定視圖類型,預設是tree。
文字類型的字段-password="True"-以密碼的形式顯示,而不是明碼。
二進制類型的字段-filename-儲存文件名稱。
One2many字段-mode-指定視圖類型,預設是tree。
l 文字類型的字段才可使用的widget屬性內容:
email-顯示郵件中寄送目的信箱。
url-處理成可以點擊的超連結。
html-將文字呈現為HTML內容。
email-顯示郵件中寄送目的信箱。
url-處理成可以點擊的超連結。
html-將文字呈現為HTML內容。
l 數值類型的字段才可使用的widget屬性內容:
handle-專門為列表視圖中的序號字段設計的,允許拖曳以調整順序。
float_time-格式化浮點數字段。
monetary-顯示浮點數貨幣金額,需要綁定字段,例如options="{'currency_field': 'currency_id'}"。
progressbar-以百分比的形式展示浮點數。
handle-專門為列表視圖中的序號字段設計的,允許拖曳以調整順序。
float_time-格式化浮點數字段。
monetary-顯示浮點數貨幣金額,需要綁定字段,例如options="{'currency_field': 'currency_id'}"。
progressbar-以百分比的形式展示浮點數。
l 關聯選擇類型的字段才可使用的widget屬性內容:
many2many_tags-將值顯示為一列按鈕標籤。
selection-是Many2one字段使用的選項列表組件。
radio-單選按鈕。
priority-星級評分的形式。
state_selection-為看板狀態的選項列表展示信號燈。
many2many_tags-將值顯示為一列按鈕標籤。
selection-是Many2one字段使用的選項列表組件。
radio-單選按鈕。
priority-星級評分的形式。
state_selection-為看板狀態的選項列表展示信號燈。
l 可用於控制特定用戶介面元素的可見性:
groups-可以根據目前使用者所屬的security決定視圖元素的可見性。
states-可以根據紀錄的state字段切換視圖元素的可見性。
groups-可以根據目前使用者所屬的security決定視圖元素的可見性。
states-可以根據紀錄的state字段切換視圖元素的可見性。
XML視圖元素本書範例
l 表頭(header):
<header>
<!--以按鈕、狀態等組件為例-->
<!--stage是使用支持模型來設置流程的各個步驟-->
<!--state是選擇列表-->
<!--widget="statusbar"表示文檔在當前所在流程階段中的點-->
<!--clickable="True"允許使用者點擊狀態欄來更改文檔所處的流程階段-->
<!--status_visible屬性列出狀態欄中可用的狀態-->
<field name="state"
widget="statusbar"
clickable="True"
status_visible="draft,open,done"/>
<!--可以使用states或attrs來實現相同的效果-->
<!--class="oe_highlight"突出顯示最重要的階段或步驟-->
<button name="do_close"
type="object"
string="關閉"
attrs="{'invisible':[('state', 'in', ['draft'])]}"
class="oe_highlight"/>
<!--options="{'fold_field': 'fold'}"摺疊很少使用的流程階段-->
<field name="stage_id"
widget="statusbar"
clickable="True"
options="{'fold_field': 'fold'}" />
</header>
<header>
<!--以按鈕、狀態等組件為例-->
<!--stage是使用支持模型來設置流程的各個步驟-->
<!--state是選擇列表-->
<!--widget="statusbar"表示文檔在當前所在流程階段中的點-->
<!--clickable="True"允許使用者點擊狀態欄來更改文檔所處的流程階段-->
<!--status_visible屬性列出狀態欄中可用的狀態-->
<field name="state"
widget="statusbar"
clickable="True"
status_visible="draft,open,done"/>
<!--可以使用states或attrs來實現相同的效果-->
<!--class="oe_highlight"突出顯示最重要的階段或步驟-->
<button name="do_close"
type="object"
string="關閉"
attrs="{'invisible':[('state', 'in', ['draft'])]}"
class="oe_highlight"/>
<!--options="{'fold_field': 'fold'}"摺疊很少使用的流程階段-->
<field name="stage_id"
widget="statusbar"
clickable="True"
options="{'fold_field': 'fold'}" />
</header>
l 工作表(sheet):
<sheet>
<!--按鈕區域添加在這-->
<div name="button_box" class="oe_button_box">
<!--class="oe_stat_button"使按鈕以矩形的形式呈現-->
<!--type設定按鈕類型-->
<!--icon設定要使用的圖像,可從Font Awesome集中選擇-->
<!--name設定要觸發的動作名稱,必須使用公式將XML ID轉換為資料庫ID:"%(action-xmlid)d"-->
<button class="oe_stat_button"
type="action"
icon="fa-tasks"
name="%(action_bug_button)d"
context="{'default_user_id': user_id}"
help="本用戶負責的所有bug">
<!--使用statinfo widget統計訊息-->
<field string="BUGs" name="user_bug_count" widget="statinfo"/>
</button>
</div>
<!--看板狀態訊號-->
<field name="kanban_state" widget="state_selection"/>
<!--畫面左上角顯示圖片-->
<field name="icon_image" widget="image" class="oe_avatar"/>
<div class="oe_title">
<!--<label>元素用於控制字段標籤顯示時間和位置-->
<!--如果元素在<group>之外則不會自動產生<label>,所以我們需要在XML中手動添加<label>-->
<!--for屬性標示我們獲取標籤文本的字段,可選擇使用string屬性替代-->
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<h3>
<span class="oe_read_only">創建者:</span>
<label for="user_id" class="oe_edit_only"/>
<field name="user_id" class="oe_inline"/>
</h3>
</div>
</sheet>
<sheet>
<!--按鈕區域添加在這-->
<div name="button_box" class="oe_button_box">
<!--class="oe_stat_button"使按鈕以矩形的形式呈現-->
<!--type設定按鈕類型-->
<!--icon設定要使用的圖像,可從Font Awesome集中選擇-->
<!--name設定要觸發的動作名稱,必須使用公式將XML ID轉換為資料庫ID:"%(action-xmlid)d"-->
<button class="oe_stat_button"
type="action"
icon="fa-tasks"
name="%(action_bug_button)d"
context="{'default_user_id': user_id}"
help="本用戶負責的所有bug">
<!--使用statinfo widget統計訊息-->
<field string="BUGs" name="user_bug_count" widget="statinfo"/>
</button>
</div>
<!--看板狀態訊號-->
<field name="kanban_state" widget="state_selection"/>
<!--畫面左上角顯示圖片-->
<field name="icon_image" widget="image" class="oe_avatar"/>
<div class="oe_title">
<!--<label>元素用於控制字段標籤顯示時間和位置-->
<!--如果元素在<group>之外則不會自動產生<label>,所以我們需要在XML中手動添加<label>-->
<!--for屬性標示我們獲取標籤文本的字段,可選擇使用string屬性替代-->
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<h3>
<span class="oe_read_only">創建者:</span>
<label for="user_id" class="oe_edit_only"/>
<field name="user_id" class="oe_inline"/>
</h3>
</div>
</sheet>
l <group>元素:
<!--<newline>元素用於<group>內強制換行-->
<!--<separator>元素用於<group>內添加一些較為重要的標題-->
<!--<group>元素的col屬性設定列數,預設為2-->
<!--放置於<group>內的元素,例如<field>元素,colspan屬性設定列數-->
<group name="group_top">
<group name="group_left">
<field name="user_id"/>
<separator string="誰關注此bug"/>
<field name="follower_id"/>
</group>
<group name="group_right">
<field name="tag_ids" widget="many2many_tags"/>
<field name="progress"/>
</group>
</group>
<!--<newline>元素用於<group>內強制換行-->
<!--<separator>元素用於<group>內添加一些較為重要的標題-->
<!--<group>元素的col屬性設定列數,預設為2-->
<!--放置於<group>內的元素,例如<field>元素,colspan屬性設定列數-->
<group name="group_top">
<group name="group_left">
<field name="user_id"/>
<separator string="誰關注此bug"/>
<field name="follower_id"/>
</group>
<group name="group_right">
<field name="tag_ids" widget="many2many_tags"/>
<field name="progress"/>
</group>
</group>
l <notebook>元素:
<!--<notebook>元素適合用於字段非常多的情況-->
<notebook>
<page string="選項卡名" name="technical name">
<field name="name field">
</page>
<page>
<!--第二個選項卡內容-->
</page>
</notebook>
<!--<notebook>元素適合用於字段非常多的情況-->
<notebook>
<page string="選項卡名" name="technical name">
<field name="name field">
</page>
<page>
<!--第二個選項卡內容-->
</page>
</notebook>
看板視圖
l 表單視圖是以XML元素為主的,例如<field>和<group>等,使用HTML的元素比較少;看板視圖將主要使用HTML元素,使用的XML元素僅為<field>和<button>兩個。
l Web客戶端中呈現的最終HTML是從QWeb模板動態生成的;QWeb引擎可處理特定的XML標記和屬性,生成對應的HTML。
l 單純看板視圖-承襲上例,在views資料夾內修改openacademy_hierarchy.xml:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_openacademy_hierarchy_tree" model="ir.ui.view">
<field name="name">view.openacademy.hierarchy.tree</field>
<field name="model">openacademy.hierarchy</field>
<field name="arch" type="xml">
<tree string="">
<field name="name"/>
<field name="parent_id"/>
</tree>
</field>
</record>
<record id="view_openacademy_hierarchy_form" model="ir.ui.view">
<field name="name">view.openacademy.hierarchy.form</field>
<field name="model">openacademy.hierarchy</field>
<field name="arch" type="xml">
<form string="">
<sheet>
<group>
<field name="name"/>
<field name="parent_id"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="openacademy_hierarchy_kanban" model="ir.ui.view">
<field name="name">openacademy.hierarchy.kanban</field>
<field name="model">openacademy.hierarchy</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<kanban>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_card">
<a type="open">
<field name="name"/>
<field name="parent_id"/>
</a>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="action_openacademy_hierarchy_view" model="ir.actions.act_window">
<field name="name">層級範例資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.hierarchy</field>
<field name="view_mode">tree,form,kanban</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_openacademy_hierarchy_tree" model="ir.ui.view">
<field name="name">view.openacademy.hierarchy.tree</field>
<field name="model">openacademy.hierarchy</field>
<field name="arch" type="xml">
<tree string="">
<field name="name"/>
<field name="parent_id"/>
</tree>
</field>
</record>
<record id="view_openacademy_hierarchy_form" model="ir.ui.view">
<field name="name">view.openacademy.hierarchy.form</field>
<field name="model">openacademy.hierarchy</field>
<field name="arch" type="xml">
<form string="">
<sheet>
<group>
<field name="name"/>
<field name="parent_id"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="openacademy_hierarchy_kanban" model="ir.ui.view">
<field name="name">openacademy.hierarchy.kanban</field>
<field name="model">openacademy.hierarchy</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<kanban>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_card">
<a type="open">
<field name="name"/>
<field name="parent_id"/>
</a>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="action_openacademy_hierarchy_view" model="ir.actions.act_window">
<field name="name">層級範例資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.hierarchy</field>
<field name="view_mode">tree,form,kanban</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
</data>
</odoo>
l Upgrade Module:
l
階段看板視圖一-承襲前一系列學習筆記範例,在views資料夾內修改openacademy_student.xml;灰色框架為QWeb設定,暫時省略:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_openacademy_student_tree" model="ir.ui.view">
<field name="name">view.openacademy.student.tree</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<tree string="">
<field name="student_no"/>
<field name="student_name"/>
<field name="student_employee"/>
<field name="student_contact"/>
<field name="student_class"/>
<field name="student_birthday"/>
<field name="student_fm"/>
<field name="student_memo"/>
</tree>
</field>
</record>
<record id="view_openacademy_student_form" model="ir.ui.view">
<field name="name">view.openacademy.student.form</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<form string="">
<sheet>
<group>
<field name="student_no"/>
<field name="student_name"/>
<field name="student_employee"/>
<field name="student_contact"/>
<field name="student_class"/>
<field name="student_birthday"/>
<field name="student_fm"/>
<field name="student_memo"/>
<field name="student_obj"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<record id="view_openacademy_student_kanban" model="ir.ui.view">
<field name="name"> view.openacademy.student.kanban</field>
<field name="model">openacademy.student</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<!--class="o_kanban_small_column"卡片的展示比較緊湊-->
<kanban default_group_by="student_class" class="o_kanban_small_column">
<!--progressbar進度條屬性-->
<!--field設定階段列中的項目進行顏色分組-->
<!--danger是紅色,warning是黃色,success是綠色-->
<!--sum_field階段列卡片的匯總字段,預設計算項目數,此處未使用-->
<progressbar field="student_fm" colors='{"M": "danger", "F": "success"}'/>
<!--HTML模板-->
<templates>
<t t-name="kanban-box">
<!--HTML QWeb template-->
<div class="oe_kanban_card">
<a type="open">
<field name="student_name"/>
<field name="student_fm"/>
</a>
</div>
<!--定義kanban-box模板-->
<!--設置kanban卡片颜色-->
<div t-attf-class=" oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown">
<!--卡片右上方按鈕在這裡定義-->
</div>
<div class="oe_kanban_body">
<!--看板的字段在這裡定義-->
</div>
<div class="oe_kanban_footer">
<div class="oe_kanban_footer_left">
<!--頁腳左區域-->
</div>
<div class="oe_kanban_footer_right">
<!--頁腳右區域-->
</div>
</div>
<div class="oe_clear"/>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="search_openacademy_student_view" model="ir.ui.view">
<field name="name">search.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<search string="">
<field name="student_name" filter_domain="['|', '|', ('student_name', 'ilike', self), ('student_no', 'ilike', self), ('student_fm', 'ilike', self)]"/>
</search>
</field>
</record>
<record id="action_openacademy_student_view" model="ir.actions.act_window">
<field name="name">學生基本資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.student</field>
<field name="view_mode">tree,form,kanban</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
<!-- Add Text Here -->
</p><p>
<!-- More details about what a user can do with this object will be OK -->
</p>
</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_openacademy_student_tree" model="ir.ui.view">
<field name="name">view.openacademy.student.tree</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<tree string="">
<field name="student_no"/>
<field name="student_name"/>
<field name="student_employee"/>
<field name="student_contact"/>
<field name="student_class"/>
<field name="student_birthday"/>
<field name="student_fm"/>
<field name="student_memo"/>
</tree>
</field>
</record>
<record id="view_openacademy_student_form" model="ir.ui.view">
<field name="name">view.openacademy.student.form</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<form string="">
<sheet>
<group>
<field name="student_no"/>
<field name="student_name"/>
<field name="student_employee"/>
<field name="student_contact"/>
<field name="student_class"/>
<field name="student_birthday"/>
<field name="student_fm"/>
<field name="student_memo"/>
<field name="student_obj"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<record id="view_openacademy_student_kanban" model="ir.ui.view">
<field name="name"> view.openacademy.student.kanban</field>
<field name="model">openacademy.student</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<!--class="o_kanban_small_column"卡片的展示比較緊湊-->
<kanban default_group_by="student_class" class="o_kanban_small_column">
<!--progressbar進度條屬性-->
<!--field設定階段列中的項目進行顏色分組-->
<!--danger是紅色,warning是黃色,success是綠色-->
<!--sum_field階段列卡片的匯總字段,預設計算項目數,此處未使用-->
<progressbar field="student_fm" colors='{"M": "danger", "F": "success"}'/>
<!--HTML模板-->
<templates>
<t t-name="kanban-box">
<!--HTML QWeb template-->
<div class="oe_kanban_card">
<a type="open">
<field name="student_name"/>
<field name="student_fm"/>
</a>
</div>
<!--定義kanban-box模板-->
<!--設置kanban卡片颜色-->
<div t-attf-class=" oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown">
<!--卡片右上方按鈕在這裡定義-->
</div>
<div class="oe_kanban_body">
<!--看板的字段在這裡定義-->
</div>
<div class="oe_kanban_footer">
<div class="oe_kanban_footer_left">
<!--頁腳左區域-->
</div>
<div class="oe_kanban_footer_right">
<!--頁腳右區域-->
</div>
</div>
<div class="oe_clear"/>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="search_openacademy_student_view" model="ir.ui.view">
<field name="name">search.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<search string="">
<field name="student_name" filter_domain="['|', '|', ('student_name', 'ilike', self), ('student_no', 'ilike', self), ('student_fm', 'ilike', self)]"/>
</search>
</field>
</record>
<record id="action_openacademy_student_view" model="ir.actions.act_window">
<field name="name">學生基本資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.student</field>
<field name="view_mode">tree,form,kanban</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
<!-- Add Text Here -->
</p><p>
<!-- More details about what a user can do with this object will be OK -->
</p>
</field>
</record>
</data>
</odoo>
l
Upgrade Module:
l 階段看板視圖二(未實作,僅提供框架)-承襲階段看板視圖一,在views資料夾內修改openacademy_student.xml之QWeb框架:
<!--其餘省略-->
<templates>
<t t-name="kanban-box">
<!--HTML QWeb template-->
<!--定義kanban-box模板-->
<!--設置kanban卡片颜色-->
<div t-attf-class=" oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown">
<!--卡片右上方按鈕在這裡定義-->
<a class="dropdown-toggle btn" data-toggle="dropdown" href="#">
<span class="fa fa-ellipsis-v" aria-hidden="true"/>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<!--編輯動作-->
<t t-if="widget.editable">
<li><a type="edit">編輯</a></li>
</t>
<t t-if="widget.deletable">
<li><a type="delete">刪除</a></li>
</t>
<!--調用伺服器端模型方法-->
<t t-if="!record.is_closed.value">
<li><a name="do_toggle_done" type="object">關閉bug</a></li>
</t>
<!--顏色選項-->
<li class="divider"/>
<li class="dropdown-header">顏色</li>
<li>
<ul class="oe_kanban_colorpicker" data-field="color"/>
</li>
</ul>
</div>
<div class="oe_kanban_body">
<!--看板的字段在這裡定義-->
<div>
<field name="tag_ids"/>
</div>
<div>
<strong>
<a type="open"><field name="name" /></a>
</strong>
</div>
<ul>
<li><field name="user_id"/></li>
<li><field name="deadline"/></li>
</ul>
</div>
<div class="oe_kanban_footer">
<div class="oe_kanban_footer_left">
<!--頁腳左區域-->
<field name="priority" widget="priority"/>
</div>
<div class="oe_kanban_footer_right">
<!--頁腳右區域-->
<field name="kanban_state" widget="kanban_state_selection"/>
<img t-att-src="kanban_image(
'res.users', 'image_small', record.user_id.raw_value)"
t-att-title="record.user_id.value"
width="24"
height="24"
class="oe_kanban_avatar"/>
</div>
</div>
<div class="oe_clear"/>
</div>
</t>
</templates>
<!--其餘省略-->
<templates>
<t t-name="kanban-box">
<!--HTML QWeb template-->
<!--定義kanban-box模板-->
<!--設置kanban卡片颜色-->
<div t-attf-class=" oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown">
<!--卡片右上方按鈕在這裡定義-->
<a class="dropdown-toggle btn" data-toggle="dropdown" href="#">
<span class="fa fa-ellipsis-v" aria-hidden="true"/>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<!--編輯動作-->
<t t-if="widget.editable">
<li><a type="edit">編輯</a></li>
</t>
<t t-if="widget.deletable">
<li><a type="delete">刪除</a></li>
</t>
<!--調用伺服器端模型方法-->
<t t-if="!record.is_closed.value">
<li><a name="do_toggle_done" type="object">關閉bug</a></li>
</t>
<!--顏色選項-->
<li class="divider"/>
<li class="dropdown-header">顏色</li>
<li>
<ul class="oe_kanban_colorpicker" data-field="color"/>
</li>
</ul>
</div>
<div class="oe_kanban_body">
<!--看板的字段在這裡定義-->
<div>
<field name="tag_ids"/>
</div>
<div>
<strong>
<a type="open"><field name="name" /></a>
</strong>
</div>
<ul>
<li><field name="user_id"/></li>
<li><field name="deadline"/></li>
</ul>
</div>
<div class="oe_kanban_footer">
<div class="oe_kanban_footer_left">
<!--頁腳左區域-->
<field name="priority" widget="priority"/>
</div>
<div class="oe_kanban_footer_right">
<!--頁腳右區域-->
<field name="kanban_state" widget="kanban_state_selection"/>
<img t-att-src="kanban_image(
'res.users', 'image_small', record.user_id.raw_value)"
t-att-title="record.user_id.value"
width="24"
height="24"
class="oe_kanban_avatar"/>
</div>
</div>
<div class="oe_clear"/>
</div>
</t>
</templates>
列表視圖
l 列表視圖的<tree>元素範例:
<tree decoration-muted="is_closed" decoration-bf="state=='open'" delete="false">
<tree decoration-muted="is_closed" decoration-bf="state=='open'" delete="false">
l 列表視圖的<tree>元素屬性:
decoration-NAME-進行顏色與字體動態更改,NAME若是bf為粗體,NAME若是it為斜體。
default_order-重寫模型的預設排序順序。
create-可以設定false禁止對應的操作。
edit-可以設定false禁止對應的操作。
delete-可以設定false禁止對應的操作。
editable-可使紀錄可以直接在列表視圖中進行編輯,值是top或bottom。
decoration-NAME-進行顏色與字體動態更改,NAME若是bf為粗體,NAME若是it為斜體。
default_order-重寫模型的預設排序順序。
create-可以設定false禁止對應的操作。
edit-可以設定false禁止對應的操作。
delete-可以設定false禁止對應的操作。
editable-可使紀錄可以直接在列表視圖中進行編輯,值是top或bottom。
搜索視圖
l 搜索視圖的<search>元素範例-承襲前一系列學習筆記範例,在views資料夾內修改openacademy_student.xml:
<record id="search_openacademy_student_view" model="ir.ui.view">
<field name="name">search.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<search string="">
<!--如果要在搜索框中輸入內容,會出現帶有student_no與student_name提示的下拉框-->
<field name="student_no"/>
<field name="student_name"/>
<!--"一年級"與"三年級"同時使用會進行OR計算-->
<filter name="student_class" string="一年級" domain="[('student_class','=','1')]"/>
<filter name="student_class" string="三年級" domain="[('student_class','=','3')]"/>
<!--根據student_fm進行分組過濾-->
<filter name="student_fm" string="按性別分組" context="{'group_by': 'student_fm'}"/>
</search>
</field>
</record>
<record id="search_openacademy_student_view" model="ir.ui.view">
<field name="name">search.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<search string="">
<!--如果要在搜索框中輸入內容,會出現帶有student_no與student_name提示的下拉框-->
<field name="student_no"/>
<field name="student_name"/>
<!--"一年級"與"三年級"同時使用會進行OR計算-->
<filter name="student_class" string="一年級" domain="[('student_class','=','1')]"/>
<filter name="student_class" string="三年級" domain="[('student_class','=','3')]"/>
<!--根據student_fm進行分組過濾-->
<filter name="student_fm" string="按性別分組" context="{'group_by': 'student_fm'}"/>
</search>
</field>
</record>
l Upgrade Module:
l 搜索視圖的<field>元素屬性:
name-標示字段名字。
string-用於定義字段的標籤文字。
operator-可用於修改運算子,而不使用預設運算子,數值字段可使用"=",其它類型字段則使用"ilike"。
filter_domain-為operator屬性提供一種靈活的替代方法。
groups-搜索僅適用於某些security。
name-標示字段名字。
string-用於定義字段的標籤文字。
operator-可用於修改運算子,而不使用預設運算子,數值字段可使用"=",其它類型字段則使用"ilike"。
filter_domain-為operator屬性提供一種靈活的替代方法。
groups-搜索僅適用於某些security。
l 搜索視圖的<filter>元素屬性:
name-非必需,標示字段名字。
string-必需,用於定義字段的標籤文字。
domain-域表達式。
context-使用字典將分組字段設定為value。
groups-設定可以執行搜索的security。
name-非必需,標示字段名字。
string-必需,用於定義字段的標籤文字。
domain-域表達式。
context-使用字典將分組字段設定為value。
groups-設定可以執行搜索的security。
日曆視圖
l 日曆視圖的<calendar>元素範例-承襲前一系列學習筆記範例,在views資料夾內修改openacademy_student.xml:
<record id="calendar_openacademy_student_view" model="ir.ui.view">
<field name="name">calendar.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<calendar date_start="student_birthday" color="student_no">
<!--展示字段定義在這裡-->
<field name="student_name"/>
<field name="student_fm"/>
</calendar>
</field>
</record>
<!--加上calendar視圖模式-->
<record id="action_openacademy_student_view" model="ir.actions.act_window">
<field name="name">學生基本資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.student</field>
<field name="view_mode">tree,form,Kanban,calendar</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
<record id="calendar_openacademy_student_view" model="ir.ui.view">
<field name="name">calendar.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<calendar date_start="student_birthday" color="student_no">
<!--展示字段定義在這裡-->
<field name="student_name"/>
<field name="student_fm"/>
</calendar>
</field>
</record>
<!--加上calendar視圖模式-->
<record id="action_openacademy_student_view" model="ir.actions.act_window">
<field name="name">學生基本資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.student</field>
<field name="view_mode">tree,form,Kanban,calendar</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
l Upgrade Module:
l 日曆視圖的<calendar>元素屬性:
date_start-必需,日曆視圖中,紀錄的開始日期。
date_end-日曆視圖中,紀錄的結束日期。
date_delay-持續的天數,若設定了就不需要設定date_end。
all_day-為布林類型,設定全天事件之後,持續期間將會被忽略。
color-用於為日曆視圖中的一組實體設定顏色。
mode-表示日曆的預設顯示週期為每日、每週或每月。
date_start-必需,日曆視圖中,紀錄的開始日期。
date_end-日曆視圖中,紀錄的結束日期。
date_delay-持續的天數,若設定了就不需要設定date_end。
all_day-為布林類型,設定全天事件之後,持續期間將會被忽略。
color-用於為日曆視圖中的一組實體設定顏色。
mode-表示日曆的預設顯示週期為每日、每週或每月。
l 日曆視圖的<calendar>元素屬性avatar_model處理Many2many字段:
.py檔內的欄位-
employee_id = fields.Many2many('hr.employee', string='雇員', index=True)
.xml檔內的屬性-
<calendar date_start="date_r1" date_stop=" date_r2" color="employee_id" avatar_model="hr.employee">
<!--展示字段定義在這裡-->
</calendar>
.py檔內的欄位-
employee_id = fields.Many2many('hr.employee', string='雇員', index=True)
.xml檔內的屬性-
<calendar date_start="date_r1" date_stop=" date_r2" color="employee_id" avatar_model="hr.employee">
<!--展示字段定義在這裡-->
</calendar>
圖表視圖與樞紐分析視圖
l 圖表視圖的<graph>元素範例-承襲前一系列學習筆記範例,在views資料夾內修改openacademy_student.xml:
<record id="graph_openacademy_student_view" model="ir.ui.view">
<field name="name">graph.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<!--除了bar之外(累積直方圖須使用屬性stacked="True"),還可以使用pie或line-->
<graph type="bar">
<field name="student_name"/>
<field name="student_fm"/>
</graph>
</field>
</record>
<!--加上graph視圖模式-->
<record id="action_openacademy_student_view" model="ir.actions.act_window">
<field name="name">學生基本資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.student</field>
<field name="view_mode">tree,form,Kanban,calendar,graph</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
<record id="graph_openacademy_student_view" model="ir.ui.view">
<field name="name">graph.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<!--除了bar之外(累積直方圖須使用屬性stacked="True"),還可以使用pie或line-->
<graph type="bar">
<field name="student_name"/>
<field name="student_fm"/>
</graph>
</field>
</record>
<!--加上graph視圖模式-->
<record id="action_openacademy_student_view" model="ir.actions.act_window">
<field name="name">學生基本資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.student</field>
<field name="view_mode">tree,form,Kanban,calendar,graph</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
l Upgrade Module:
l 樞紐分析視圖的<pivot>元素範例-承襲前一系列學習筆記範例,在views資料夾內修改openacademy_student.xml:
<record id="pivot_openacademy_student_view" model="ir.ui.view">
<field name="name">pivot.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<pivot>
<field name="student_fm" type="col"/>
<field name="student_name" type="measure"/>
<field name="student_birthday" interval="year"/>
</pivot>
</field>
</record>
<!--加上pivot視圖模式-->
<record id="action_openacademy_student_view" model="ir.actions.act_window">
<field name="name">學生基本資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.student</field>
<field name="view_mode">tree,form,Kanban,calendar,graph,pivot</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
<record id="pivot_openacademy_student_view" model="ir.ui.view">
<field name="name">pivot.openacademy.student.view</field>
<field name="model">openacademy.student</field>
<field name="arch" type="xml">
<pivot>
<field name="student_fm" type="col"/>
<field name="student_name" type="measure"/>
<field name="student_birthday" interval="year"/>
</pivot>
</field>
</record>
<!--加上pivot視圖模式-->
<record id="action_openacademy_student_view" model="ir.actions.act_window">
<field name="name">學生基本資料</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">openacademy.student</field>
<field name="view_mode">tree,form,Kanban,calendar,graph,pivot</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create"></p>
<p></p>
</field>
</record>
l Upgrade Module:
l 圖表視圖與樞紐分析視圖的<field>元素屬性:
name-標示在視圖中使用的字段名稱。
type-可用於設定字段的使用方式,可以是measure或者col,其中col 只能在樞紐分析圖中使用。
interval-是日期字段的屬性,可用於設定時間間隔,可以是day、week、month、quarter或者year。
group_operator-屬性設定avg、max、min等聚合運算,預設為總和。
name-標示在視圖中使用的字段名稱。
type-可用於設定字段的使用方式,可以是measure或者col,其中col 只能在樞紐分析圖中使用。
interval-是日期字段的屬性,可用於設定時間間隔,可以是day、week、month、quarter或者year。
group_operator-屬性設定avg、max、min等聚合運算,預設為總和。
辛苦了 odoo的開發真的架構是比較大並且套路是自成一格
回覆刪除當時也是花了一些時間去上課,並且研究很多的原生模組以及OCA模組才比較能加速掌握
可惜因為疫情關係一直無法順利的把元植流的odoo開發班開起來
如果還有機會想要在嘗試看看也可以在關注odoo社群的發展~
加油,共勉之!
元植流 總顧問 林敬雲
如果你有意願跟我們一起在台推廣odoo
刪除也可以參考我們的人才招募歐~
https://www.yuanchih-consult.com/blog/4/post/78
謝謝,元植是台灣少數堅持推動Odoo社群發展的公司。
刪除