2020年6月1日 星期一

Odoo快速入門與實戰學習筆記

  此篇筆記為承襲前一系列Odoo教育訓練學習筆記,擷取簡體書《Odoo快速入門與實戰》至第12章的內容,收錄前一系列學習筆記缺乏的部分,主要為網頁控制器和視圖層的基本介紹,並參雜一些常用元件的說明;此書後續章節包含QWeb等功能的說明則未收錄於此筆記。

  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')
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>
l   修改__manifest__.py
#
原程式碼增加以下程式碼
'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
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>
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模型的紀錄對象


層級結構關係
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)
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>
l   設置__init__.py__manifest__.pyopenacademy_menu.xmlir.model.access.csv等檔案之後Upgrade Module


引用字段的動態關係
l   承襲上例,在models資料夾內修改openacademy_hierarchy.py
#
原程式碼增加以下程式碼
dynamic_user = fields.Reference([('res.users', '
用戶'), ('res.partner', '合作伙伴')], '使用者')
l   設置openacademy_hierarchy.xml等檔案之後Upgrade Module


通信API
l   __manifest__.py增加以下程式碼:
'depends': ['mail']
l   承襲前一系列學習筆記範例,在models資料夾內修改openacademy_student.py
#
抽象模型沒有對應的資料表,不能被直接使用,而是做為混合類別來使用;它提供了現成的功能模板,用的時候需繼承使用
_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>
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>
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')
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>
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('
%dbug'%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>


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"
-該字段必填。
l   按鈕字段才可使用的屬性:
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>
l   特定字段才可使用的屬性:
文字類型的字段-password="True"-以密碼的形式顯示,而不是明碼。
二進制類型的字段-filename-儲存文件名稱。
One2many
字段-mode-指定視圖類型,預設是tree
l   文字類型的字段才可使用的widget屬性內容:
email
-顯示郵件中寄送目的信箱。
url
-處理成可以點擊的超連結。
html
-將文字呈現為HTML內容。
l   數值類型的字段才可使用的widget屬性內容:
handle
-專門為列表視圖中的序號字段設計的,允許拖曳以調整順序。
float_time
-格式化浮點數字段。
monetary
-顯示浮點數貨幣金額,需要綁定字段,例如options="{'currency_field': 'currency_id'}"
progressbar
-以百分比的形式展示浮點數。
l   關聯選擇類型的字段才可使用的widget屬性內容:
many2many_tags
-將值顯示為一列按鈕標籤。
selection
-是Many2one字段使用的選項列表組件。
radio
-單選按鈕。
priority
-星級評分的形式。
state_selection
-為看板狀態的選項列表展示信號燈。
l   可用於控制特定用戶介面元素的可見性:
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"/>
    <!--
可以使用statesattrs來實現相同的效果-->
    <!--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>
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>
l   <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>
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>
l   Upgrade Module


l   階段看板視圖二(未實作,僅提供框架)-承襲階段看板視圖一,在views資料夾內修改openacademy_student.xmlQWeb框架:
<!--
其餘省略-->
    <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">
l   列表視圖的<tree>元素屬性:
decoration-NAME
-進行顏色與字體動態更改,NAME若是bf為粗體,NAME若是it為斜體。
default_order
-重寫模型的預設排序順序。
create
-可以設定false禁止對應的操作。
edit
-可以設定false禁止對應的操作。
delete
-可以設定false禁止對應的操作。
editable
-可使紀錄可以直接在列表視圖中進行編輯,值是topbottom

搜索視圖
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_nostudent_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
l   搜索視圖的<filter>元素屬性:
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>
l   Upgrade Module


l   日曆視圖的<calendar>元素屬性:
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>

圖表視圖與樞紐分析視圖
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"),還可以使用pieline-->
        <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>
l   Upgrade Module


l   圖表視圖與樞紐分析視圖的<field>元素屬性:
name
-標示在視圖中使用的字段名稱。
type
-可用於設定字段的使用方式,可以是measure或者col,其中col 只能在樞紐分析圖中使用。
interval
-是日期字段的屬性,可用於設定時間間隔,可以是dayweekmonthquarter或者year
group_operator
-屬性設定avgmaxmin等聚合運算,預設為總和。

3 則留言:

  1. 辛苦了 odoo的開發真的架構是比較大並且套路是自成一格
    當時也是花了一些時間去上課,並且研究很多的原生模組以及OCA模組才比較能加速掌握

    可惜因為疫情關係一直無法順利的把元植流的odoo開發班開起來
    如果還有機會想要在嘗試看看也可以在關注odoo社群的發展~

    加油,共勉之!
    元植流 總顧問 林敬雲

    回覆刪除
    回覆
    1. 如果你有意願跟我們一起在台推廣odoo
      也可以參考我們的人才招募歐~

      https://www.yuanchih-consult.com/blog/4/post/78

      刪除
    2. 謝謝,元植是台灣少數堅持推動Odoo社群發展的公司。

      刪除