iT邦幫忙

2023 iThome 鐵人賽

DAY 3
0
Odoo

Odoo16 入門介紹系列 第 3

Day3_odoo_Model介紹

  • 分享至 

  • xImage
  •  

Model

現在開始,會進行無氧運動,你必須先有印象,筆者希望讀者在看的時候可以邊做筆記邊記憶,在Odoo當中,Model所扮演的腳色,主要是與DB溝通,也就是CRUD,相信接觸過MVC或是MTV架構的讀者不會陌生,這個功能就是ORM,我們可以透過ORM使的我們在撰寫程式時,規避掉很多資安上的問題,在這邊筆者就不細談,讀者可以透過Google或是ChatGPT去了解,當我們透過撰寫Model,使用ORM來創建DB中的Table,而這些Table的資料,我們在odoo中稱他們為record。

○ (model.Models) - 最常使用的model類型

my_module/init.py 在開始controller設定之前,我們必須先將我們models給import進去
from . import models
my_module/models/init.py 在開始controller設定之前,我們必須先將我們models.py給import進去
from . import library_model

○ 種類和使用

from odoo import models,fielsd,api

class Library(models.Model):
    _name = 'library.book'
    _description = 'library.book'
    _inherit='mail'
    _order='sequence,name'

name: model的名稱。
description: model檢的的描述。
inherit:繼承自這個model的屬性。
order: 主要是排序,跟SQL中的order by是類似的。
當我們想要呼叫Library當中的欄位資料時,我們可以使用self.env['library.book']

fields.Char() - 常用屬性有string(代表欄位的名子)跟size(可以設定最長長度)
fields.Text() - 常用屬性為string(代表欄位的名子)
fields.Integer() - 常用屬性為string(代表欄位的名子)
fields.Float() - 常用屬性有string(代表欄位的名子)跟digits(通常會是一個tuple並且分別代表('總位數','小數精度'))
fields.Html() - 常用屬性為string(代表欄位的名子)
fields.Date() - 常用屬性string(代表欄位的名子)或是default=lambda = self:fields.Date.now()
fields.Datetime() - 常用屬性string(代表欄位的名子)或是default=lambda = self:fields.Datetime.now()
fields.Binary() - 常用屬性為string(代表欄位的名子)
fields.Selection() - 常用屬性有items(會是一個[list])跟string(代表欄位的名子)。

#Date()Datetime()還有這些類型:

fields.Date.to_date(string_value)
fields.Date.to_string(date_value)
fields.Date.today()
fields.Date.context_today(record, timestamp)
---------------------------------------------
fields.Datetime.to_date(string_value)
fields.Datetime.to_string(datetime_value)
fields.Datetime.today()
fields.Datetime.context_today(record, timestamp)

上面這些都是常用的欄位常用的屬性:

string: 欄位名稱
required: 必填欄位
help: 提示訊息
compute : 可以對欄位的資料做及時的計算,不會回存到table中但可以透過store=True來進行儲存。
default : 設定預設值。
translate : 通常在CharTextHtml中使用,主要使用在翻譯。
readonly : 預設為False,只可以讀不能編輯
index : 設定為True之後,會優先被查找減輕DB負載。
copy : 設定該欄位能不能被複製。
groups : 設定只有該群組可以看到欄位。
states : 通常長這樣{'done':['readonly',True]},用這樣的方式來設定欄位只能被讀。還可以設定
required、invisible。
deprecated : 只要將其設定為True,會在日誌中記錄警告訊息。
active : 如果降他設定為False,當前端在查詢時將會被忽略。
sequence : 必須在_order中引入,可以手動定義record順序。
related : 透過關聯把資料拉出來,不會儲存在DB中,與fields.selection()搭配使用。
gender = fields.Selection('Gender', related='employee_id.gender')

○ @api

常用的@api有以下這些:

@api.model - 通常會運用在修改既有CRUD函式時會呼叫它,而在odoo16它已經取代了@api.one與@api.multi的功能了。
@api.constrains(" ") - 主要的功能是在約束fields,與_sql_constraints是擁有相同的功能。
@api.depends(" ") - 通常與compute一起使用,只能在view上做操作,操作過的record不會儲存在table中。
@api.onchange(" ") - 可以對record資料做計算,但只能在同一model中做使用。
大多數情況,使用@api都是為了DB效能而使用,當你使用方法在抓取recordset的時候你沒有使用@api ,odoo會預設為@api.model來實行。

內建的CRUD(創建、讀、更新、刪除):

read([])
create({})
write({})
unlink()
browse(int)
※括弧當中所代表的是,填寫資料的屬性如'[]'代表字串、'{}'代表字典、'int'代表整數。
search() 當我們想使用其他model的recordset的時候,我們可以這樣做:

def other_recordset(self):
    all_members=self.env['library.member'].search([])
    print("All members:",all_members)
    return True

或是我們想要創建一個新record:

record=self.evn['library.book.category'].create(parent_category_val)
還可以更新record:

def update_record(self):
    self.ensure_one()
    self.date_release=fields.Date.today()
------------------------------------------
def update_record(self):
    self.ensure_one()
    self.update({'date_release':'fields.Date.today()'})

我們也可以透過write({})來對record的操作

record.write({'child_ids':[0,0,child]})
record.write({'child_ids':[1,child_index,update_child]})

這邊詳細介紹這些( , , )內所代標的意思

(0,0,{a:b})   - 創建record,並且將{a:b}關聯
(1,id,{a:b})  - 更新id值為id的record,並且將{a:b}關聯
(2,id,)       - 刪除id值為id的record
(3,id,)       - unlink id值為id的record
(4,id,)       - link id值為id的record
(5,0,0)       - 刪除所有的 link record
(6,0,[ids])      - 替換現有的 link record

○ 報錯

from odoo.exceptions import UserError
from odoo.tools.translate import _

首先我們要import UserError_

@api.model
def change_state(self, new_state):
    for book in self:
        if book.is_allowed_transition(book.state, new_state):
            book.state = new_state
        else:
            msg = _('Moving from %s to %s is not allowed') % (book.state, new_state)
            raise UserError(msg)

這邊這段程式碼的用意,主要確認借書狀態是否可以更新,如果不行將回傳Error給使用者,其中_ 在未來翻譯多國語言的時候可以用到。

ValidationError() -沒有滿足constrains條件報錯
AccessError() -用戶不是群組內的使用者,不得訪問
RedirectError() -報出Error後,指向指定View當中
這些是其他常用報錯的字段

○ Filter record

如果我們想要將特定的record找出來我們可以透過以下方法:

@api.model
def multiple_authors(self,all_book):
    def predicate(book):
        if len(book.author_ids)>1:
            return True
        return all_book.filter(predicate)
@api.model
def get_author_names(self,books):
    return book.mapped('author_ids.name')
或是排序record:

@api.mode
def sort_book_by_date(self,books):
    return books.sorted(key='release_date')

○ sudo()

當我們遇到需要特定全線record時,想將資料呈現給不再此群組中的使用者看,可以使用:

def book_rent(self):
    self.ensure_one() #這段在使用sudo()時,非常重要必定要搭配使用
    if self.state !='avaliable':
        raise UserError(_('book is not available for renting!!'))
        rent_as_superuser=self.env['library.book.rent'].sudo()
        rent_as_superuser.create({'book_id':self.id,
                                  'borrower_id':self.env.user.partner_id.id,})

另外還有兩種model:

model.AbstractModel - 通常會跟report一起使用,並且資料不會被儲存或是在進行運算,不想讓DB的負擔太大。
model.transientModel - 通常會用在引導用戶使用,並且是臨時儲存的,在一定的時間內就會被系統刪除舊的數據。


上一篇
Day2_odoo_環境建設(2)
下一篇
Day4_odoo_Model介紹(2)
系列文
Odoo16 入門介紹30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言