今天會來學習其他繼承的機制,用來擴充我們的應用程式,總共會有4種,分別是:
我們先用classic extension擴充model,根據原有model定義要更改或新增的欄位屬性,我們會做:
先到library_member/models/library_book.py新增以下:
isbn = fields.Char(help="Use a valid ISBN-13 or ISBN-10.")
publisher_id = fields.Many2one(index=True)
再到添加,這樣就能讓check ISBN支援10位碼:
def _check_isbn(self):
self.ensure_one()
digits = [int(x) for x in self.isbn if x.isdigit()]
if len(digits) == 10:
ponderators = [1, 2, 3, 4, 5, 6, 7, 8, 9]
total = sum(a * b for a, b in zip(digits[:9], ponderators))
check = total % 11
return digits[-1] == check
else:
return super()._check_isbn()
這種繼承方式,比較不像物件繼承,比較像物件組合。
等等要實作的是要讓會員可以借書,並擁有借書卡,會員資料會組合在一起,而不是繼承。
先在library_member/model/init.py:
from . import library_member
到library_member/models/library_member.py
from odoo import fields, models
class Member(models.Model):
_name = "library.member"
_description = "Library Member"
_inherits = {"res.partner": "partner_id"}
_inherit = ["mail.thread", "mail.activity.mixin"]
card_number = fields.Char()
partner_id = fields.Many2one(
"res.partner", delegate=True, ondelete="cascade", required=True
)
要完成這個model還要新增安全性ACL、menu item和 view:
新增安全性ACL,library_member/security/ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_member_user,Member User # 跟下面的要連著
Access,model_library_member,library_app.library_group_user,1,1,1,0
access_member_manager,Member # 要跟下面的連著
ManagerAccess,model_library_member,library_app.library_group_manager,1,1,1,1
新增 menu item,library_member/views/library_menu.xml
<odoo>
<menuitem id="menu_library_member"
name="Members"
action="action_library_member"
parent="library_app.menu_library" />
</odoo>
新增view,library_member/views/member_view.xml
<odoo>
<record id="view_form_member" model="ir.ui.view">
<field name="name">Library Member Form
View</field>
<field name="model">library.member</field>
<field name="arch" type="xml">
<form>
<group>
<field name="name" />
<field name="email" />
<field name="card_number" />
</group>
</form>
</field>
</record>
<record id="view_tree_member" model="ir.ui.view">
<field name="name">Library Member List
View</field>
<field name="model">library.member</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="card_number" />
</tree>
</field>
</record>
</odoo>
最後要到library_member/manifest.py宣告
"data": [
"security/ir.model.access.csv",
"views/book_view.xml",
"views/library_menu.xml",
],
升級model後,就能使用這個擴充model。
這邊要練習將message chatter and activity mixins 兩種功能結合到library_member上,
要到library_member/manifest.py修改depend mail
"depends": ["library_app", "mail"],
到library_member/models/library_member.py 新增
_inherit = ["mail.thread", "mail.activity.mixin"]
最後再到library_member/views/member_view.xml,新增mail mixin field那邊的code
<record id="view_form_member" model="ir.ui.view">
<field name="name">Library Member Form
View</field>
<field name="model">library.member</field>
<field name="arch" type="xml">
<form>
<group>
<field name="name" />
<field name="email" />
<field name="card_number" />
</group>
<!-- add mail mixin field -->
<div class="oe_chatter">
<field name="message_follower_ids"
widget="mail_followers"/>
<field name="activity_ids"
widget="mail_activity"/>
<field name="message_ids"
widget="mail_thread"/>
</div>
</form>
</field>
</record>
這樣到library Members form 就能使用留言版的功能,也有給web client使用的一些功能。
語法小推薦 enumerate
method _check_isbn
下方兩行的可以簡化
ponderators = [1, 2, 3, 4, 5, 6, 7, 8, 9]
total = sum(a * b for a, b in zip(digits[:9], ponderators))
改用 enumerate
,可以省掉宣告 ponderators
total = sum(a * b for a, b in enumerate(digits[:9], start=1))
而我個人的寫法會變成這樣,任何不符合規則的都先提早離開 method,儘量讓主程式在同一階層,分享給您
def _check_isbn(self) -> bool:
self.ensure_one()
digits = [int(x) for x in self.isbn if x.isdigit()]
if not len(digits) == 10:
return super()._check_isbn()
check = sum(i * d for i, d in enumerate(digits[:9], start=1)) % 11
return digits[-1] == check
PS:最後兩行也可以省略成一行,但後續可能回憶會太亂還是保留兩行
嗨嗨,感謝指點,
很認同你的重構,大大提升了可讀性,還補上 type hint,Python 的功力真高!
我們寫的比較倉促,想要一路從 Model 做到 Front-end,程式還沒整理完,之後每章節會補上 git commit。