「Odoo 基礎教程系列」第二篇——從 Todo 應用開始(1)

By PickPik

在第一篇教程發佈以後差很少一個月的今天,終於完成了第二篇內容,這個發佈週期拖得實在是有點太長了,我都以爲很差意思了?python

從這一篇教程開始,咱們將以建立一個 Todo 應用爲目標,將 Odoo 中的一些概念和內容逐漸引入進來,而後利用這些知識去完善咱們的 Todo 應用。雖然這是個很簡單的應用,可是但願你們能夠動手一塊兒操做,從最簡單的開始上手學習如何使用 Odoo 這個框架。git

這篇教程將會帶領你們一塊兒建立第一個 Odoo 模塊,爲模型增長菜單和修改視圖,對於剛接觸的小夥伴來講可能會有些生澀,不理解也不要緊,慢慢接觸上手以後會顯得容易得多,同時也歡迎你們積極提問,我會竭盡所能去幫助愛學習的小夥伴的。github

好了,下面就正式開始,一塊兒動手完成這一次的內容吧?shell

建立模塊

咱們在 Odoo 源碼所在目錄的同一層級裏建立一個目錄 mkdir mymodules,這個目錄專門用於存放咱們本身建立的模塊,和 Odoo 自帶的模塊區分開來,固然你也能夠用其餘名字。而後用 odoo-bin 的腳手架功能建立一個空的 Odoo 模塊,裏面包含了一個完整的項目所需的基本文件和項目結構:數據庫

./odoo/odoo-bin scaffold todo mymodules

進去 mymodules/ 看看,是否是多了一個目錄 todo/?就是這麼簡單,咱們的第一個 Odoo 模塊就建立好了,接下來先對項目結構進行簡單的說明,瞭解一下各個目錄底下應該放置些什麼內容。segmentfault

結構說明

下面是咱們剛建立的 todo 模塊的目錄結構,從上到下一一進行說明:瀏覽器

todo
├── __init__.py
├── __manifest__.py
├── controllers
│   ├── __init__.py
│   └── controllers.py
├── demo
│   └── demo.xml
├── models
│   ├── __init__.py
│   └── models.py
├── security
│   └── ir.model.access.csv
└── views
    ├── templates.xml
    └── views.xml

在 Python 中,每個包(package)都包含一個 __init__.py 文件,而一個 Odoo 的模塊,同時也是一個 Python 包,因此咱們能夠看到,生成的項目文件裏已經包含了 __init__.py 這個文件,若是打開這個文件,你會看到裏面引入了 controllersmodels 這兩個包,稍候咱們會講到這兩個,這裏先放一放。那麼對於這個 __init__.py 文件,咱們沒什麼特殊需求,是能夠不用去理會的,就讓它靜靜地躺在那裏完成它的使命就行了。安全

文件 __manifest__.py 用於聲明一個 Odoo 模塊以及指定它的元數據(metadata),文件裏只包含了一個單獨的 Python 字典,裏面默認只列出了 9 項最基本的配置項,包含了模塊(或應用)名,模塊的簡介和詳細介紹,做者和網站,模塊的所屬分類、版本,還有就是這個模塊依賴於其餘的哪些 Odoo 模塊,須要加載哪些數據文件以及演示數據。除了這裏列出的配置項外,還有一些高級配置項,咱們這裏暫時不須要理會,後面用到以後將會進行詳細的說明。微信

接下來咱們先講一下 demosecurity 這兩個目錄。前者是用於存放演示數據的,在 __manifest__.py 中就能夠看到有引入該目錄下的 demo.xml 文件,在使用演示模式時,初始化一些演示數據能夠幫咱們節省很多的時間;然後者經過名字就知道它的做用是跟安全相關的,目錄下只有一個 ir.model.access.csv 文件,裏面用於定義不一樣的角色組對應於不一樣模型的相關權限,包括讀(read),寫(write),建立(create)和刪除(unlink)權限,擁有相關權限則爲 1,反之爲 0。咱們剛提到了角色組,可是沒有發現相關定義的位置,咱們只要默認角色組的定義和模型權限定義在同一目錄下就能夠了,角色組的定義一樣也是使用的 .xml 文件,在後面咱們會有專門的一篇文章對角色組和權限進行講解說明。框架

下面要講的是 Odoo 開發中的核心部分 MVC(同時也是大部分 Web 應用開發所採用的經典模式),MVC 分別表明的是 Model(模型)、View(視圖)和 Controller(控制器)。有關 MVC 模式具體的概念和相關的知識,這裏就不做詳細講解了,但願不瞭解的同窗能夠去找找相關的內容學習一下。這裏簡單說一下它們各自的用途,在 Model 中,咱們定義一切和數據相關的東西,例如對應到數據庫表字段的模型字段、各類外鍵關係以及操做數據的邏輯方法等。View 則是負責數據展現的,咱們經過編寫視圖控制須要展現出來的數據以及以什麼樣的形式展現數據等,而且能夠在視圖上進行交互。Controller 則是在 Model 和 View 之間,負責響應用戶操做,從 Model 中獲取數據進行處理並返回到 View 中。

以上就是對一個 Odoo 模塊的目錄結構的一些簡單的說明,另外還有一些目錄在初始建立的模塊裏是沒有出現的,可是咱們後面會用上,到時候本身手動建立相應的目錄便可。

模型

前面一節中咱們說到 Model 是用於定義和數據相關內容的地方,如今就來建立第一個模型吧。

首先打開 models/models.py 將裏面註釋掉的內容刪掉,不要修改文件頂部引入的包,而後添加如下代碼:

class TodoTask(models.Model):
     _name = 'todo.task'
     _description = '待辦事項'

     name = fields.Char('描述', required=True)
     is_done = fields.Boolean('已完成?')

看起來十分簡單,第一個模型就這樣建立好了 :)

咱們建立了一個叫作 TodoTask 的類,它繼承自基礎模型 models.Model,這也是咱們使用 Odoo 開發時最經常使用的一種用於持久化數據的基礎模型,除此以外還有 models.TransientModelmodels.AbstractModel 這兩種,在以後接觸到咱們將會進行講解,這裏暫不涉獵。

先看一下這個模型裏帶下劃線前綴的兩個屬性:

  • _name - 模型的名稱,在外鍵或者實例化模型對象時會用到,是模型的惟一標識
  • _description - 模型的描述,描述模型的做用,通常狀況下不會主動使用到

除了上面列出的兩個特殊屬性外,還有一些其餘屬性,例如更改默認顯示名稱時會用到 _rec_name,繼承現有模型時會用到 _inherit 等,這些特殊屬性都具備他們各自的用途,可是除了 _name 是定義一個新的模型時必需要有的屬性外,其餘屬性都是可選的。

在 Odoo 的模型定義中,咱們使用 fields 進行字段的定義,在上面這個模型裏,咱們簡單地定義了 nameis_done 兩個字段,它們的類型分別是 CharBoolean,而且咱們指定字段 name 是必填的(添加了 required=True)。若是小夥伴接觸過 Django,可能就會說了,Django 的 CharField 是必須指定最大長度 max_length 的,Odoo 的不須要嗎?那最大長度是多少呢?對於這個疑問,官方的文檔裏有這樣一句說明:

Basic string field, can be length-limited, usually displayed as a single-line string in clients.

也就是說 Odoo 的字段類型 Char 是不限制長度的,可是一般只是用於單行字符串,若是要存儲大量文本內容,仍是使用 Text 更合適一些。

不如咱們先把模塊安裝好,看看會不會有什麼事情發生,和上一篇教程同樣,咱們先將 Odoo 服務跑起來,記得先在 Odoo 的源碼目錄中激活咱們的開發環境:

pipenv shell

./odoo-bin --addons-path=addons,../mymodules --db-filter=^demo$ -d demo

須要注意一下的是 --addons-path 中除了有 addons 外,還加上了咱們剛建立的模塊目錄 mymodules,這裏使用的是相對路徑,不要搞錯了哦 :)

接下來咱們打開瀏覽器訪問 localhost:8069 而後用超級管理員賬號登陸(不記得了?賬號密碼都是 admin),登陸後在應用列表頁面,將搜索框的 Apps 標籤去掉,搜索關鍵詞 todo 找到咱們剛建立的模塊,點擊 Install 按鈕安裝模塊。好了,你很快就會發現,頁面又倒回了應用列表頁面,若是咱們再次按前面的步驟搜索咱們的模塊,你會發現沒有了安裝按鈕,如今顯示的是 Installed 已安裝,除了這個變化外彷彿一切都沒發生過,這是爲何呢?

由於咱們沒有入口,找不到能夠打開咱們的 Todo 應用的地方,接下來咱們就一塊兒建立第一個入口——菜單。

建立菜單

光有模型是固然不夠的,就好象一幢大樓,鋼筋骨架都搭起來了,而後把牆給封死了,沒有門咱們進不去呀!

恰好像說了個不怎麼恰當的比喻,不如直接動手,建立一個菜單更實際。在模塊裏的 views 目錄下建立一個 menus.xml 文件,而後輸入如下內容:

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data>
        <!-- 主菜單定義 -->
        <menuitem id="menu_todo" name="Todo"/>
        <!-- 菜單動做定義 -->
        <record id="action_todo_task" model="ir.actions.act_window">
            <field name="name">待辦事項</field>
            <field name="res_model">todo.task</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form</field>
            <field name="target">current</field>
        </record>
        <!-- 子菜單定義 -->
        <menuitem action="action_todo_task" id="submenu_todo_task" name="待辦事項"
                  parent="menu_todo" sequence="10"/>
    </data>
</odoo>

上面各部份內容我都寫上了備註,你們一看就應該知道它們各自是幹什麼的了。在 Odoo 中定義一個菜單,使用的是 menuitem,而後咱們須要爲菜單指定屬性 idname,前者是這個菜單的惟一標識,然後者則是這個菜單所顯示的名字。

而後咱們定義了一個菜單動做,也就是點擊一個菜單時所要執行的動做,Odoo 中動做的類型分爲幾個類型,從 model 這個屬性能夠看出來一個動做是屬於什麼類型的,act_window 表示咱們定義的這個動做是和窗口有關的,例如打開一個彈窗或者一個列表頁面,均可以經過窗口動做實現。其餘類型的動做咱們先放一放,後面會有專門的一篇文章用於講述動做相關的內容,咱們先簡單地瞭解一下定義一個窗口動做有哪些要素。

和定義菜單同樣,必不可少的會有 id 這一屬性,之後咱們將默認全部在 .xml 文件中定義的數據,都須要帶有 id 屬性,畢竟這是咱們可以經過代碼找到它們的惟一標識了。這裏咱們用了 record 標籤,包裹了一系列的 field 來定義咱們的動做,除了能夠定義動做外,包括前面提到的菜單在內的一切具備實際模型的對應的數據,咱們均可以這樣定義,最大的區別就在於 model 這個屬性所指定的值,它對應到咱們定義的數據是來自哪一個模型的,被包裹在裏面的 field 則對應到一個模型的各個字段。剛開始可能不太明白,不過沒關係,後面會一直使用到,很快就能掌握的了。

最後咱們定義了一個子菜單,能夠看到和最開始定義的菜單不同的是,咱們這裏多了 3 個屬性,分別是 actionparentsequence。其中 action 的值是咱們定義的動做的 id,表示點擊這個菜單,就執行對應 id 的動做,parent 指定的值是咱們定義的第一個菜單的 id,表示當前菜單是指定菜單的子菜單,sequence 用於指定當前菜單的位置,若是咱們在主菜單下有多個子菜單,咱們能夠經過這個屬性去指定各個子菜單排列的前後順序。

關於菜單和動做,暫時就先到這裏,最後不要忘了把文件 menus.xml 放到 __manifest__.pydata 列表中,否則咱們定義的內容是不會被加載的哦:

# 如今應該是這樣的
'data': [
    # 'security/ir.model.access.csv',
    'views/views.xml',
    'views/templates.xml',
    'views/menus.xml',
],

好咧,菜單有了,也就有了入口,如今咱們刷新頁面看看有沒有什麼變化,好像仍是同樣沒有什麼不同?固然了,由於咱們修改了模塊裏的文件內容,這些變更並無被加載,因此咱們須要先升級模塊。同樣的步驟,先找到咱們的 Todo 應用模塊,而後點擊卡片進入表單頁面,能夠看到有個 Upgrade 按鈕,咱們點擊這個按鈕把模塊升級一下,而後你就會發現,咱們終於看到了期待已久的菜單和 Todo 應用的列表頁面啦~

待辦事項列表頁

咱們的 Todo 應用已經初具原型了,點擊 Create 按鈕,建立一些數據試試看吧 :)

還記得在建立模型的時候給字段 name 加上了一個 required=True 的屬性嗎?在建立記錄的表單頁咱們能夠看到,這個字段是淡紫色背景的,這說明這一項是必填的內容,若是不填寫,點擊 Save 按鈕,就會發現標籤顯示的「描述」變成了紅色,輸入框也被紅色邊框包裹起來了,而且能夠看到在窗口右上角出現了一個警告提示。

待辦事項表單頁警告

在建立好一條待辦事項的記錄後,點擊 Save 保存,若是想要繼續建立,能夠直接在表單頁上點擊 Create 繼續建立新的記錄,也能夠返回列表頁查看所有的待辦事項記錄。若是完成了一個待辦事項,咱們點擊對應的記錄,進入到表單頁面,而後點擊 Edit 編輯按鈕,而後勾選「已完成?」表示咱們已經完成了這個任務。

想要刪除掉一些記錄該怎麼辦?能夠在列表頁先勾選須要刪除的記錄,而後點擊上面的 Action 菜單,能夠看到 Delete 這個選項,點擊後會詢問是否要刪除,點擊 Ok 確認就能夠刪除啦~除了列表頁上能夠刪除記錄,還能打開一條待辦事項進入表單頁面,而後打開 Action 菜單執行刪除操做。

建立視圖

在建立菜單以後,咱們直接就看到了相應的列表和表單頁面,但是咱們並無建立任何相關的內容,這是 Odoo 自動幫咱們作了處理。若是一個模型沒有建立對應的視圖(View),Odoo 就會根據默認的規則進行顯示。

但是默認在列表頁只顯示了一個 name 字段,咱們想要知道一個事項是否完成了,並不能直接在列表頁上知道,須要一個個點擊進去查看,若是有不少的記錄,這可就太蛋疼了!因此咱們仍是須要本身建立一個列表視圖,把是否已完成顯示在列表頁上。

打開 views/views.xml,把裏面註釋掉的內容都刪掉,而後添加如下內容:

<odoo>
    <data>
        <record id="todo_task_view_tree" model="ir.ui.view">
            <field name="name">todo.task.view_tree</field>
            <field name="model">todo.task</field>
            <field name="type">tree</field>
            <field name="arch" type="xml">
                <tree string="Todo">
                    <field name="name"/>
                    <field name="is_done"/>
                </tree>
            </field>
        </record>
    </data>
</odoo>

建立視圖相關的內容,咱們須要指定屬性 model="ir.ui.view",而後還有兩個關鍵的地方是 type 的值,若是建立的是列表視圖,則填寫 tree,若是是表單視圖則是 form,除了這兩種視圖外還有其餘類型的視圖,咱們暫時不會接觸到。而後是 arch 的值,裏面的內容決定了咱們的視圖長什麼樣,列表視圖須要用 <tree></tree> 包裹起來,表單視圖則是 <form></form>,包裹的內容具會有所不一樣,這裏咱們只須要在列表視圖中將要顯示的字段列舉出來便可。

完成這一切以後,升級一下模塊,而後看看效果如何。

修改後的列表頁

能夠看到列表裏多了一列「已完成?」,這樣咱們就能夠一目瞭然,知道哪些事項是已經完成了的,而後就能夠直接勾選將他們刪除掉啦 XD

源碼下載

從這一篇教程開始,我會把全部代碼提交到 Github 的倉庫中,而且我會保留相應的文件修改的 commits 以供追溯,你們能夠經過查看 commits 看到各個文件的變更,若是發現什麼問題,也能夠直接提 issue 尋求幫助?

倉庫地址:Odoo-Tutorial-Demo

相關文章

微信羣

最後慣例,感興趣的小夥伴能夠加入微信羣一塊兒交流,加好友時備註加羣,接受後會拉進羣內。

微信號

相關文章
相關標籤/搜索