odoo之技巧合集一

YifChan發表於2021-01-25

羅列一些odoo開發中的簡單但有效的方法;

1.重寫odoo登入程式碼

參考連結:odoo10-重寫登入方法

from odoo import models, fields, api, SUPERUSER_ID

class Users(models.Model):
    _inherit = "res.users"
    @classmethod
    def _login(cls, db, login, password):
        user_id = super(Users, cls)._login(db, login, password)

        """自定義程式碼部分開始"""
        data = {
            'user': user_id,
            'message': u"使用者登入了系統"
        }
        with cls.pool.cursor() as cr:
            self = api.Environment(cr, SUPERUSER_ID, {})[cls._name]
            self.env['system_log.login_log'].sudo().create(data)
        """自定義程式碼部分結束"""

        return user_id

 

2.使用jinja2在odoo中返回自定義的html頁面

返回一個login.html頁面

def get_env(self):
    if hasattr(sys, 'frozen'):
        # When running on compiled windows binary, we don't have access to package loader.
        path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'views'))
        loader = jinja2.FileSystemLoader(path)
    else:
        loader = jinja2.PackageLoader('odoo.addons.module_name', "views")
    env = jinja2.Environment(loader=loader, autoescape=True)
    return env

env = self.get_env()
return env.get_template('login.html').render({"request": request, "errmsg": ""})

 

3.在controller中操作別的/指定資料庫的資料

在odoo.register()中指定資料庫

import odoo
import odoo.modules.registry

registry = odoo.registry(request.session.db)
with registry.cursor() as cr:
    env = api.Environment(cr, SUPERUSER_ID, {})
    rec = env["res.users"].search([('login', '=', request.params['login'])])

 

4.自定義記錄表示標題_rec_name

記錄顯示標題可採用一個魔法計算欄位display_name,odoo會⾃動新增它到所有模型 中。它的值由name_get() 模型⽅法⽣成,name_get()的預設實現使⽤_rec_name屬性來查詢放置資料的欄位,使⽤它⽣成顯示名稱。 如果你想要⾃⼰實現顯示名稱,可以過載name_get()中的邏輯來⽣成⼀個⾃定義顯示名稱。 該⽅法應返回⼀個包含兩個元素的列表,格式:[(id,  unicode_str)]。

例如:

class LibraryBook(models.Model):
    _name = "library.book"
    _rec_name = "short_name"

    name = fields.Char(string="Title", required=True)
    short_name = fields.Char(string="Short Name", required=True)
    date_release = fields.Date(string="Release Date")

    def name_get(self):
        result = []
        for rec in self:
            rec_name = "{}_{}".format(rec.name, rec.date_release)
            data = (rec.id, rec_name)
            result.append(data)
        return result

 

5.模型父子級索引優化

我們啟動了對於等級的特別⽀持。這是⼀個⾮常有⽤的⾼讀取低寫⼊指令,因為 它通過更⼤的寫⼊運算開銷帶來了更快速的資料瀏覽。這通過新增⼀個幫助欄位parent_path 及設定模型屬性為 _parent_store=True來實現。在啟⽤了這個屬性之後,該幫助欄位會⽤於 在等級樹的搜尋中儲存資料。預設,它假定記錄的⽗級欄位名為parent_id,但也可以使⽤不 同的名稱。這種情況下,正確的欄位名應使⽤額外的模型屬性_parent_name來進⾏表明。

class BookCategory(models.Model):
    _name = "library.book.category"
    # 新增如下程式碼啟動特別的等級支援
    _parent_store = True
    _parent_name = "parent_id"
    parent_path = fields.Char(index=True)

    name = fields.Char(string="Category")
    parent_id = fields.Many2one("library.book.category", string="Parent Category", ondelete="restrict", index=True)
    child_ids = fields.One2many("library.book.category", "parent_id", string="child Category")

詳情可以檢視anlan hou的 odoo12開發者指南第五章-應用模型;

 

6.計算欄位的可編輯和可搜尋

計算欄位是在 運⾏時動態計算的,並且除⾮你⾃⼰特別的新增⽀持,否則它們是不可寫、不可搜尋的。 計算欄位在運⾏時動態計算,但ORM使⽤快取來避免在每次訪問值時的低效重計算。
因此, 它需要知道所依賴的其它欄位。它使⽤@depends裝飾器來監測快取值何時應置為⽆效並重 新計算。

確保compute函式總是為計算欄位設定⼀個值。否則會丟擲錯誤。這在程式碼中包含if條件⽽ 對計算欄位設定值失敗時會發⽣。那樣會很難進⾏除錯。

準備

date_release = fields.Date(string="Release Date")
# 計算欄位,及讓計算欄位可編輯和可搜尋
age_days = fields.Float(string="Days Since Release", compute="_compute_age", inverse="_inverse_age",
                        search="_search_age", store=False, compute_sudo=False)

# 值計算邏輯的方法
@api.depends("date_release")
def _compute_age(self):
    today = fields.Date.today()
    for book in self.filtered("date_release"):  # 篩選有 date_release 的書籍
        delta = today - book.date_release
        book.age_days = delta.days

計算欄位逆向編輯

寫操作可通過實現inverse函式來新增。這使⽤分配給計算欄位的值來更新原欄位。
# 新增方法及實現客入計算欄位的邏輯
def _inverse_age(self):
    today = fields.Date.today()
    for book in self.filtered("date_release"):  # 篩選有 date_release 的書籍
        d = today - timedelta(days=book.age_days)
        book.date_release = d

計算欄位可搜素

可以通過將search屬性設定為⽅法名(類似compute和inverse)來讓⾮儲存的計算欄位可 搜尋。這個⽅法預期不實現實際的搜尋。⽽是接收⽤於搜尋該欄位的運算子和值來作為參 數,並預期返回⼀個帶有⽤於替換搜尋條件的域。

# 實現允許你在計算欄位中進行搜尋的邏輯;將對計算欄位 age_days 的搜尋轉換為對 age_days 依賴的 date_release 欄位的搜尋
def _search_age(self, operator, value):  # =, 7
    today = fields.Date.today()  # 2021,1,18
    value_days = timedelta(days=value)
    value_date = today - value_days
    operator_map = {
        '>': '<', '>=': '<=',
        '<': '>', '<=': '>=',
    }
    new_op = operator_map.get(operator, operator) # =
    res = [('date_release', new_op, value_date)]  # [('date_release', '=', datetime.date(2021, 1, 11))]
    return res

 

7.使用mail模組記錄欄位改變

在__manifest__.py中繼承 mail 模組

'depends': ['base', 'mail'],

在需要記錄的模型中繼承mail的相關模型

_inherit = ['mail.thread', 'mail.activity.mixin']

在需要記錄的欄位後面新增追蹤屬性 track_visibility

title = fields.Char(string="標題", required=True, readonly=True, states={'draft': [('readonly', False)]}, track_visibility="onchange")

在模型的form檢視上新增記錄的欄位

<sheet>
...
</sheet>
<div class="oe_chatter">
    <field name="message_ids" widget="mail_thread"/>
</div>

 

8.使用者自定義引用的模型及記錄(使用引用欄位新增動態關聯)

在n2n中,我們可以固定提供使用者選用的某條記錄 ,比如使用者要選擇書籍中的紅樓夢那條記錄。但是有時候這不足以滿足我們的需求,此時,我們可以讓使用者自己選擇想要關聯的模型及記錄。我們通過引用欄位來實現。

@api.model  # 在模型級別而不是記錄集級別上進行操作
def _referencable_models(self):
    models = self.env['ir.model'].search([])
    return [(x.model, x.name) for x in models]

ref_doc_id = fields.Reference(selection='_referencable_models', string="Reference Document")

 

9.使用可配置精度的浮點欄位

odoo自帶Decimal Precision configuration模組外掛提供了這一功能。

步驟:安裝模組,在配置中新增Usage,然後在模型欄位中使用它。

1.搜尋Decimal應用,點選安裝;

2.啟用開發者模式;進入設定--技術--資料庫結構--小數準確性;建立一條記錄,設定Usage為Book Price並選擇數字精度,例如:

用途:Book Price
數字:3  # 表示小數位

3.在__manifest__.py宣告檔案中新增這個新依賴。如下:

"depends": ['base', 'decimal_precision'],  # 該模組所直接依賴的模組技術名稱列表 # 第二個為可配置浮點數精度模組

4.使用數字精度設定新增模型欄位

from addons import decimal_precision as dp
cost_price = fields.Float(string="Book Cost", digits=dp.get_precision('Book Price'))

顯示結果:

Book Cost:99.000

執行原理:

get_precision()函式查詢數字精度中的Usage欄位並返回一個16位精度的元組以及在配置中所定義的小數位數。

待。。。

 

相關文章