1. 程式人生 > 實用技巧 >Odoo快速入門與實踐 | 技術研發篇 | 自建應用入門

Odoo快速入門與實踐 | 技術研發篇 | 自建應用入門

自建應用入門

github地址

https://github.com/rowrycho/Odoo_bug_manage

講解視訊地址

還在錄製...

Odoo快速入門與實踐 | 技術研發篇 | 目錄

https://www.cnblogs.com/Rowry/p/13348205.html

目錄

目錄

在Odoo的開發過程中,建立自己的模組是非常重要的

.

  • 前面已經提到過: 不建議直接修改原始碼.

  • 所以即便是修改已有的模組,也最好是新建一個模組,然後繼承已有的模型進行擴充套件增強.

在admin使用者的登入介面裡,為什麼設定前面的選單稱為應用而不是叫做模組呢?

  • 這是因為模組應用本身就是不同的,應用是一個獨立的系統,比如HR,CRM等,而模組這只是一組較為獨立的功能,比如HR(應用)的招聘模組.
  • 雖然招聘這個功能較為獨立,但是很少有公司使用一個只有招聘功能的系統,但卻有很多公司使用HR系統,這就是應用模組的區別.
  • 一般來講,應用在Odoo裡面有一個頂級選單,而很多模組只是在這些頂級選單的下面增加的子選單或動作,這也是本書經常將模組稱為外掛模組
    的原因--因為模組往往已經是存在與應用中的外掛了.

在本章中,我們將建立自己的第一個應用,並且在這個應用過程中介紹Odoo自建應用的主要流程和節點.

對於本次的專案,我們先做一個bug管理系統,通過Odoo來完成一個bug提交,bug狀態修改等功能的模組,希望能夠以此瞭解建立自建模組的步驟.

前面已經介紹過,Odoo的整體架構是MVC分層設計的,所以在實現bug管理系統的過程中,我們會接觸到model層,view層,controller層,然後再設定本專案的訪問控制器.

完成本章後,我們能夠了解Odoo的基本構造,並可以重新開始體驗一個專案的過程.

使用腳手架建立新模組

一組獨立的功能按照不同的模組外掛進行設計

是Odoo的一個特點,這樣可以方便新增一些特性,也便於進行功能的迭代開發.

  • 要了解一個模組的結構,可以通過其檔案__manifest__.py來了解,該檔案中列出了包含哪些檢視,模型和演示資料,並且還可以配置本模組說明等基本資訊,每個模組都必須包含這個檔案.

前文中已經提到過,不建議直接修改已有的程式碼,而是需要自建一個新的模組.

  • 我們只要自己配置好一個第三方的模組存放路徑,並在 odoo.conf(配置檔案)中進行宣告

  • 使用如下命令建立模組: python odoo-bin scaffold bug_manage myaddons

  • 下面來看看該模組的檔案結構:

  • 此時開啟__manifest__.py檔案,可以看到裡面是以字典形式存放的資料(一個{}),下面我們對檔案內各個關鍵字(或者稱為引數)的意義進行解釋

  • 我們根據自己的需求,只調整調整前面的幾個引數即可,其他使用檔案給出的預設值即可.

安裝和更新模組

我們已經建立了自己的模組,雖然沒有進行業務邏輯和檢視的開發,但是現在已經可以安裝到Odoo了.

  • 在初期瞭解Odoo的階段,建議各位讀者每進行一小步都及時進行測試,這樣便於及時發現問題(測試不一定是"高大上"的,直接點選檢視效果測試,或者直接輸出print(),就是最簡單粗暴的但是非常有效的測試,更加專業的測試應該個測試工程師去做)

所以本節首先介紹如何安裝模組以及如何升級,並且介紹伺服器的開發模型.

安裝模組是在前端完成的,我們使用admin使用者登入Odoo系統並按照以下步驟進行操作:

  1. 點選 設定 介面右下角的 啟用開發者模式 進入開發者模式.
  2. 應用 介面點選左側的 更新應用列表 按鈕, 在彈出的對話方塊中點選 更新 按鈕.
  3. 然後搜尋框中搜索bug,進行安裝

如果後續對本模組進行了修改,那麼可以繼續使用該方法,只是到時候圖表右下角會出現升級按鈕,點選升級即可,也是要先更新應用列表.

因為Odoo服務只在啟動的時候對Python程式碼載入過一次,所以如果修改了Python程式碼,則需要重新啟動Odoo.

  • 更為安全的方式時在重啟服務的時候,加上更新的引數: python odoo-bin -d 資料庫名字 -u 要更新模組的名稱
  • 當然,如果把 -u 替換為 -i,這樣就可以安裝模組了,對於Odoo11來說,還是在前端頁面安裝給更為方便一些.

注意: 如果希望在修改了Python程式碼之後不重啟伺服器就能讓修改起作用,那麼可以使用Odoo的伺服器開發模式,只需要加上一個引數 -dev=all即可

  • 在伺服器開發模式下,每當我們儲存Python檔案時,伺服器都會重新載入程式碼,這樣就極大的加快了開發週期(其實不是很推薦)

下面我們通過一個小例子來檢視升級的功能,我們為bug管理應用新增一個圖示

  • 我們需要bug_manage專案下建立目錄\static\description,並將圖示命名為icon.png

  • 點選 更新應用列表,既可以看到這個新增的圖示

模型

我們已經在Odoo安裝了自己的模組(module),現在可以新增自己的模型(models)了.

  • 模型可用於描述業務物件,如訂單,憑證等. (所有的物件都是可以使用欄位來抽象資訊化表示的)
  • 模型是通過繼承Odoo模板的Python類(odoo.models.Model)進行增強擴充套件來實現的.
  • 建立模型後,Odoo會通過ORM引擎在資料庫自動建立表.

我們的模型要完成的任務也比較簡單,只是去維護bug列表.

  • 每個bug均包含描述資訊和是否完成的標示
  • 後續將再來慢慢新增一些bug關閉等功能

建立模型

我們在models資料夾下建立bugs.py檔案,然後在裡面編輯程式碼,如下:

from odoo import fields, models, api


class Bugs(models.Model):
    _name = "bm.bug"
    _description = "bug"
    name = fields.Char(string='bug簡述', required=True)
    detail = fields.Text(size=150)
    is_closed = fields.Boolean(string="是否關閉")
    close_reason = fields.Selection([("changed", "已修改"), ("cannot", "無法修改"), ("delay", "推遲"), ],
                                    string="關閉理由")
    user_id = fields.Many2one('res.users', string="負責人")
    follower_ids = fields.Many2many('res.partner', string='關注者')

關於模型的定義會在後面介紹,暫時可以將其看成是欄位.

常用屬性

從上面的例子中,我們可以看到,欄位裡面有多種屬性,此處統一對常用的屬性做一些介紹

  • string: 在前端介面看到的欄位名稱,預設是欄位的技術名稱(技術名稱就是__manifest__.py中的name).
  • required: 預設是False,如果設定成True,則在建立記錄時該欄位不允許為空.(只是在前端頁面的限制)
  • help: 在前端使用時作為提示資訊. (滑鼠懸停的時候會給出提示資訊)
  • index: 布林型別,預設為False. 如果是True,則會在資料庫的該欄位上建立索引.

保留欄位

在模型裡面,有一些欄位是系統保留的,作為開發人員不能修改這些欄位,這些保留欄位具體如下:(這些欄位是在模型定義的沒有定義的,但是Odoo會建立表的時候自動加上,所以是客觀存在的)

  • id: 這是記錄的唯一標識
  • create_date: 記錄建立的日期
  • create_uid: Many2one型別,建立該記錄的使用者
  • write_date: 記錄的最後修改日期
  • write_uid: Many2one型別,記錄的最後修改使用者
  • _last_update: 該欄位並不會實際儲存值,在這裡僅起到併發檢查的作用

如果要檢視以上欄位的具體值,

  • 可以在前端的開發者模式下,通過debug(臭蟲按鈕)的檢視元資料選項檢視資料明細
  • 也可以直接在資料庫中檢視 bm_bug 資料表

注意: name欄位是模型裡面的特殊欄位,在預設情況下該欄位的值可用來在搜尋和引用時代表一行記錄.

模型繼承

前面的章節,我們已經通過新建模型建立了Bugs模型. 在我們的引用中還有一個與bug是many2many關係的關注者,關注者就是關注bug的人,我們準備繼承res.partner進行修改.

前面新建的模型是通過Python類來完成的,擴充套件和增強已有模型也是通過Python類來完成的.

Odoo提供了三種模型的繼承機制,具體如下:

  • 經典繼承: 允許子類修改父類定義的方法,欄位,也允許新增欄位和方法.

    • 只需要使用 _inherit,預設_name欄位與繼承的模型一致(也就保證了是同一張資料表)
  • 原型繼承: 和經典繼承一樣,只不過資料表是新建了一張資料表.

    • 需要使用_inherit_name, _name和繼承的模型_name不一致(所以在資料庫中會複製原來的內容,在新建一張資料表)
    • 不推薦使用這種方式,因為會造成資料的冗餘
  • 委派: 將子類中新增的欄位與父類中的欄位進行關聯,相當於保留了父類的欄位和方法.

    • 需要一個"外來鍵欄位", 只需要使用_inherits(注意: 後面有s)

我們選擇經典繼承方式來繼承使用res.partner類,仍然是在models檔案下建立類followers.py,並且編輯程式碼:

from odoo import models, field, api


class Follower(models.Model):
    _inherit = 'res.partner'  # 繼承欄位,宣告要繼承類的_name
    bug_ids = field.Many2many('bm.bug', string="bug")  # 新增欄位

我們建立了兩個類,但是不要忘記在 models/__init__.py檔案中引入這兩個新檔案.

  • 這是Python語法習慣的要求,如果不在此處,則Odoo將無法發現這兩個檔案.
  • 我們應該在__init__.py檔案內增加如下程式碼
from . import bugs
from . import follower

注意: 應該修改了內建的res.partner,所以重新啟動Odoo伺服器會報錯

  • 解決方法: python odoo-bin -c odoo.conf -u bug_manage 啟動時候加上-u 要更新的模組

檢視

前面已經建立了模型,我們還需要前端介面,本節就來介紹檢視.

  • 注意: 在還沒有配置檢視時候,安裝了應用在前端是不會顯示的
  • 如果都是使用預設的tree,search,form,那麼配置一個menuitem和action即可

檢視是通過XML檔案來定義的,前端框架(QWeb)會解析XML檔案然後生成HTML檔案提供給瀏覽器執行.

檢視的基本元素:

  • 選單(menuitems)
  • 動作(action)
  • 列表檢視(tree)
  • 搜尋檢視(search)
  • 表單檢視(form)

我們通過後臺的views資料夾下的XML檔案來建立前端檢視. 現在,我們就為bug管理系統應用建立檢視.

新增選單

我們先來建立bug管理系統的使用者介面,需要在views資料夾下新建檔案bugs.xml,並編輯如下程式碼

<odoo>
    <data>
        <!--動作視窗可以理解為一個橋樑    檢視 <= 動作 => 選單-->
        <record model="ir.actions.act_window" id="bug_manage.action_window">
            <field name="name">bug_manage window</field>
            <field name="res_model">bm.bug</field>
            <field name="view_mode">tree,form</field>
        </record>

        <!--頂級選單-->
        <menuitem name="bug管理系統" id="bug_manage.menu_root"/>
        <!--二級選單-->
        <menuitem name="bug管理" id="bug_manage.menu_1" parent="bug_manage.menu_root"/>
        <!--三級選單  ==> 選單和動作聯絡-->
        <menuitem name="bug列表" id="bug_manage.menu_1_list" parent="bug_manage.menu_1"
              action="bug_manage.action_window"/>
    </data>
</odoo>

上述程式碼說明:

  • 注意XML是按順序解釋的,所有動作視窗必須要定義在選單之前,否則會報錯
  • 上面是比較經典的定義檢視的方式,這裡使用的都是預設的tree,search,form,如果暫時不能理解,就先記住

我們需要在__manifest__.pydata中宣告新增的bugs.xml檔案(注意: 但凡是新增的xml和csv檔案,都是需要在__manifest__.pydata欄位中進行宣告)

    'data': [
        'security/ir.model.access.csv',
        'views/views.xml',
        'views/templates.xml',
        'views/bugs.xml',
    ],

然後如果需要看到效果的話,還需要設定一下安全許可權(這裡不理解不要緊,先照做),在編輯security\ir.model.access.csv,新增如下程式碼

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_bm_bug,bug_manage.bm_bug,model_bm_bug,,1,1,1,1

如果你使用 -dev=all引數,或者直接重啟伺服器,可以看到下圖介面

因為我們所用的是系統生成的列表檢視,所以顯示的資訊只有一個name欄位

  • 之前我們說過name是特殊欄位(注意是name不是_name,後者是model的唯一標識),可以用來代表一條記錄
  • 但是如果僅僅只有這個欄位,使用起來很不方便,我們需要更多欄位欄位資訊,就需要建立自己的tree檢視

建立列表(tree)檢視

檢視資料都是儲存在資料庫ir.ui.view模型中

  • 若要向這個模型中新增之間的檢視,則需要我們在XML檔案中使用<record>元素
  • 系統會在模組安裝後解析這些XML檔案,將<record>元素中的內容插入到模型中

下面我們仍然在views/bugs.xml檔案中新增該列檢視程式碼

        <!--自定義列表(tree)檢視-->
		<record model="ir.ui.view" id="bug_manage.list">
            <field name="name">bug_manage list</field>
            <field name="model">bm.bug</field>
            <field name="arch" type="xml">
                <tree>
                    <field name="name"/>
                    <field name="is_closed"/>
                    <field name="user_id"/>
                </tree>
            </field>
        </record>

業務文件表單(form)檢視

我們在此直接跨過了普通表單檢視的操作介紹,其實普通表單檢視與前面介紹的列表檢視非常相似,只是將<tree><list>互換一下.

業務表單檢視就是在普通表單檢視的基礎上新增了<header><sheet>兩個元素,我們還是在views/bugs.xml檔案內增加如下程式碼

        <record model="ir.ui.view" id="bug_manage.form">
            <field name="name">bug_manage form</field>
            <field name="model">bm.bug</field>
            <field name="arch" type="xml">
                <form>
                    <header>
                        <!--這裡的 button的name對應於未來後臺的方法-->
                        <button name="do_close" type="object" string="關閉bug"/>
                    </header>
                    <sheet>
                        <group name="group_top" col="2">
                            <field name="name"/>
                            <field name="user_id"/>
                            <field name="is_closed"/>
                        </group>

                        <group name="group_right">
                            <field name="close_reason"/>
                            <field name="follower_ids"/>
                        </group>
                        <notebook>
                            <page string="詳細內容">
                                <field name="detail"/>
                            </page>
                        </notebook>
                    </sheet>
                </form>
            </field>
        </record>

搜尋(search)檢視

到目前為止,我們的應用已經包含了列表檢視表單檢視,而且都做了一些優化,但是現在還存在一個問題: 如果列表的記錄變多了,檢視起來不是很方便,我們還需要搜尋功能還輔助提高效率.

在沒有增加搜尋檢視之前,列表檢視的右上方已經存在一個搜尋框,這是Odoo自動新增的基於name欄位的搜尋檢視,也就是說只能通過name(這裡再次體現了name作為特殊欄位的用途)

下面就來增加一個搜尋檢視,使列表檢視可以基於name,is_closed,user_id進行搜尋,仍然是在views/bugs.xml中新增程式碼

        <!--搜尋檢視-->
        <record model="ir.ui.view" id="bug_manage.search">
            <field name="name">bug_manage search</field>
            <field name="model">bm.bug</field>
            <field name="arch" type="xml">
                <search>
                    <field name="name"/>
                    <field name="is_closed"/>
                    <field name="user_id"/>
                </search>
            </field>
        </record>

搜尋檢視往往會和預定義篩選條件一起使用,這部分內容將會結合後端檢視一起介紹.

檢視繼承

前面我們已經介紹了模型的繼承,同樣,Odoo也支援對檢視進行繼承操作.

  • 檢視的繼承也是在XML程式碼中開發的
  • 使用inherit_id屬性引用被繼承的檢視,然後就可以在子檢視中進行增強擴充套件.

結合我們的應用,關注者就算在res.partner模型的基礎之上增加bug列表(bug_ids)欄位的,所以關注者的檢視也繼承自res.partner檢視進行修改.(模型是繼承的,檢視也是繼承的就合情合理了)

現在,第一步就是要確定具體繼承自哪一個檢視(需要知道該檢視的XML ID),進入 設定 | 使用者介面 | 檢視,搜尋res.partner檢視檢視對應的外部ID

第二步需要找到具體的錨點,以此來確認我們的bug_ids最終會載入檢視的哪個位置.

  • 通常是尋找一個有name屬性的元素
  • 這裡我們以 <field name="mobile">元素作為錨點

確定好要繼承檢視的外部ID找到對應的錨點,我們可以開始進行檢視繼承了. 新建views/follower.xml檔案並 編輯程式碼

<odoo>
    <data>
        <!--現在只是在 res.partner的表單中加入一個 bug_ids 的欄位-->
        <record model="ir.ui.view" id="bug_manage.follower_form">
            <field name="name">follower_form</field>
            <field name="model">res.partner</field>
            <field name="inherit_id" ref="base.view_partner_form"/>
            <field name="arch" type="xml">
                <field name="mobile" position="after">
                    <field name="bug_ids"/>
                </field>
            </field>
        </record>

        <record model="ir.actions.act_window" id="bug_manage.follower_action_window">
            <field name="name">follower_action_window</field>
            <field name="res_model">res.partner</field>
            <field name="view_mode">tree,form</field>
        </record>

        <menuitem name="follower管理" id="bug_manage.follwer_menu" parent="bug_manage.bug_menu_root"/>

        <menuitem name="follower列表" id="bug_manage.follwer_menu_list" parent="bug_manage.follwer_menu"
                  action="bug_manage.follower_action_window"/>

    </data>
</odoo>

程式碼說明:

  • <field name="inherit_id" ref="繼承檢視的XML ID" /> 這是檢視繼承必須有的
  • 這些選擇<field name>中的name進行定位,其實還可以通過<XPath>進行定位,這個在後面會講到

__manifest__.py中引入此檔案,更新應用後,可以看到

業務邏輯

在瞭解了模型檢視以後,下面就需要關注的就是一些邏輯的具體處理.

現在我們來實現關閉bug按鈕的邏輯,邏輯在Python類中可以使用方法來完成,在檔案models/bugs.py的Bugs類中增加如下程式碼

    @api.multi
    def do_close(self):
        for item in self:
            item.is_closed = True
        return True

更新應用後,開啟一個bug(沒有可以新建),點選關閉bug按鈕,會發現是否關閉複選框已被選中.

安全性配置

Odoo可以通過安全性配置來設定到選單級和到模型級的許可權,可以具體到操作的檢視,編輯和刪除等明細操作,本節我們就來介紹一下Odoo的安全性配置.

訪問控制

我們一直使用admin使用者進行開發測試,其實,目前普通使用者還不能正常使用bug管理系統,因為我們還沒有對該系統做任何訪問設定(在Odoo12開始,admin也需要做許可權設定才能訪問)

要想檢視訪問控制相關的資訊,需要登入前端並進入 設定 | 安全 | 訪問列表 頁面.

上圖我們可以看到模型安全組的對應關係,以及其具備的增刪改查的具體許可權.

這些訪問許可權資料全部儲存在ir.model.access模型中,在我們的專案中,可以通過檔案在系統啟動時寫入該模型.

  • 因為我們是使用腳手架建立的專案,所以專案的security路徑下已經預設建立了一個檔案: ir.model.acccess.csv
  • 注意: 模型名.csv這是是規定,不能修改,這個CSV檔案會將記錄寫入對應的模型中

修改完成後不要忘記在__manifest__.py中新增該csv檔案

    'data': [
        # 注意: 許可權控制檔案要放在開頭
        'security/ir.model.access.csv',
        'views/views.xml',
        'views/templates.xml',
        'views/bugs.xml',
        'views/follower.xml',
    ],

這裡還沒有建立許可權組,如果要進行進行許可權演示的話,需要在後面講到建立許可權組在進行演示.

注意: 除了模型了訪問控制,還有行級訪問規則,其具體的記錄是存放在ir.rule模型中的,關於這點也是後面再說.

網頁和控制器

Odoo還提供了一個Web開發框架,可用於實現與後端功能高度整合的網站功能.

  • 我們在本節將會開發簡單的網站網頁用於顯示我們的bug列表,是使用者可以通過URL(http://<serverhost>:8069/bug_manage)訪問我們的頁面
  • 本節只做最基本的介紹,更深入的內容會在第11章進行詳細介紹

Web控制器是負責網頁轉發的元件,具體在技術上就是http.Controller類中定義的方法,這些方法綁定了終端頁面的URL.

  • 當URL被訪問時,控制器程式碼就會執行相應的操作將HTML呈現給使用者.
  • 對於HTML的渲染,Odoo提供了QWeb模板引擎.

應用的控制器程式碼都放在/controllers資料夾下,在此目錄中使用系統預設建立的檔案controllers.py,編輯如下程式碼

from odoo import http


class Bug(http.Controller):
    @http.route('/bug_manage')
    def bug_manage(self, **kw):
        bugs = http.request.env['bm.bug']  # 獲取 bm.bug 記錄集
        domain_bug = [('is_closed', '=', False)]  # 搜尋條件
        bugs_open = bugs.search(domain_bug)  # 返回符合搜尋條件的記錄集
        return http.request.render('bug_manage.bugs_templates', {'bugs_open': bugs_open})

上面最後使用了return http.request.render('bug_manage.bugs_templates',{}),那麼接下來我們就來建立bugs_template這個QWeb模板

<odoo>
    <data>

        <template id="bugs_templates" name="bug">
            <div class="container">
                <h1>未關閉的bug</h1>
                <t t-foreach="bugs_open" t-as="bug">
                    <div class="row">
                        <span t-field="bug.name"/>
                    </div>
                </t>
            </div>
        </template>
    </data>
</odoo>

儲存上述XML程式碼,不要忘記加入__manifest__.py檔案中,然後更新應用,訪問http://localhost:8069/bug_manage,可以看到下圖效果

總結

本章我們建立了一個bug管理模組,介紹了應用從建立到升級的全流程,並且按照模型,檢視,業務邏輯對應用進行了介紹.

讀者應該掌握了

  • 應用專案的基本架構
  • 知道如何 調整Python程式碼和XML檔案以建立自己想要的介面
  • 能夠了解Odoo中繼承的應用

本章還介紹了應用的安全性配置,包括訪問控制,網頁及控制器,讀者應該能夠根據需求進行許可權配置