柚子快報(bào)激活碼778899分享:Odoo代碼規(guī)范
http://yzkb.51969.com/
作為全球第一開(kāi)源ERP,開(kāi)源讓您根據(jù)本企業(yè)業(yè)務(wù)特性,靈活定制,實(shí)現(xiàn)動(dòng)態(tài)IT系統(tǒng),可隨業(yè)務(wù)變化優(yōu)化ERP,進(jìn)而優(yōu)化管理運(yùn)營(yíng)。
對(duì)中大型企業(yè),odoo須開(kāi)發(fā)才可落地,良好開(kāi)發(fā)規(guī)范,有助于團(tuán)隊(duì)協(xié)助,敏捷開(kāi)發(fā)上線。
odoo開(kāi)發(fā)規(guī)范
Odoo 編碼指南。Odoo 代碼質(zhì)量提高可讀性、簡(jiǎn)化維護(hù)、有助于調(diào)試、降低復(fù)雜性并可靠性。應(yīng)該應(yīng)用于每個(gè)新模塊開(kāi)發(fā)和所有新開(kāi)發(fā)。
警告 stable(穩(wěn)定)版中修改現(xiàn)有文件,原始文件樣式將嚴(yán)格取代任何其他樣式準(zhǔn)則。不要修改odoo正式發(fā)布的已有文件或代碼,以用這些準(zhǔn)則。避免中斷代碼行的修訂歷史記錄。差異應(yīng)保持最小。詳細(xì)信息,參閱odoo官方 pull request guide指南。
修改master(主開(kāi)發(fā))版本中現(xiàn)有文件,僅針對(duì) revision(正在修訂)版代碼或大數(shù)文件,將準(zhǔn)則應(yīng)用于現(xiàn)有代碼。僅當(dāng)現(xiàn)有文件結(jié)構(gòu)發(fā)生重大更改時(shí),才修改。首先執(zhí)行 move commit,才應(yīng)用與其相關(guān)更改。
模塊結(jié)構(gòu)說(shuō)明
data/:演示數(shù)據(jù)models/:模型controllers/:控制器(含HTTP路由)views/:視圖和模板static/:web資源,css/, js/, img/, lib/, ...wizard/:向?qū)Ъ耙晥Dreport/:報(bào)表tests/:單元測(cè)試
命名規(guī)范
業(yè)務(wù)model放一個(gè)文件,如模塊只含一個(gè)model,與模塊名一致。如:
models/.pymodels/.pyviews/_templates.xmlviews/_views.xmldata/_demo.xmldata/_data.xml
如:銷(xiāo)售模塊含sale_order和sale_order_line兩模型,且sale_order是主模型,所以文件命名為models/sale_order.py和 views/sale_order_views.py。
數(shù)據(jù)文件命名,按用途:demo或data。如:data/sale_order_demo.xml和data/sale_order_data.xml
模塊控制器放一個(gè)文件,名為main.py。如從另模塊繼承,則命名為.py。
統(tǒng)計(jì)報(bào)表命名: report/_report.py report/_report_views.py
可打印報(bào)表: report/_reports.py report/_templates.xml
addons//
|-- __init__.py
|-- __manifest__.py
|-- controllers/
| |-- __init__.py
| |-- .py
| `-- main.py
|-- data/
| |-- _data.xml
| `-- _demo.xml
|-- models/
| `-- .py
|-- report/
| |-- _views.xml
| |-- _reports.xml
| `-- _templates.xml
|-- security/
| |-- ir.model.access.csv
| `-- _security.xml
|-- static/
| |-- img/
| | |-- my_little_kitten.png
| | `-- troll.jpg
| |-- lib/
| | `-- external_lib/
| `-- src/
| |-- js/
| | `-- .js
| |-- css/
| | `-- .css
| |-- scss/
| | `-- .scss
| `-- xml/
| `-- .xml
|-- views/
| |-- _templates.xml
| `-- _views.xml
`-- wizard/
|-- .py
|-- _views.xml
`-- _views.xml
XML文件
定義記錄xml時(shí),需標(biāo)記:
id放model前字段(field)定義中,name放第一,其他據(jù)重要性順序放值放標(biāo)簽內(nèi),或放eval屬性中。標(biāo)簽僅用不可更新數(shù)據(jù)noupdate=1,如整xml不可更新數(shù)據(jù),則noupdate=1設(shè)在標(biāo)簽上,而不需。
view.name
object_name
Odoo定義標(biāo)簽為快捷方式:
menuitem:為ir.ui.menu快捷方式template: 表示只需arch視圖部分的QWeb視圖report: 定義報(bào)表actionact_window:當(dāng)record用不了時(shí)用它
xml_id命名
權(quán)限(Security)、視圖(View)和動(dòng)作(Action)命名規(guī)則:
菜單(menu): _menu視圖(view): _view_,view_type可取值:kanban, form, tree, search動(dòng)作(action): 主動(dòng)作命名為_action,其他動(dòng)作命名為_action_,其中用小寫(xiě)字母簡(jiǎn)單描述動(dòng)作組(group): _group_,group_name可取值:user, manager,...規(guī)則(rule): _rule_,concerned_group可取值: 模型用戶規(guī)則user, 公共用戶規(guī)則public,多公司用戶規(guī)則company
...
id="model_name_menu_root"name="Main Menu"sequence="5"/>id="model_name_menu_action"name="Sub Menu 1"parent="module_name.module_name_menu_root"action="model_name_action"sequence="10"/>...............注意視圖名(name)用點(diǎn)表示法:my.model.view_type 或者my.model.view_type.inherit繼承XML命名繼承視圖命名規(guī)則:_inherit_,其中_inherit_是擴(kuò)展視圖模塊技術(shù)名稱(chēng)。...PythonOdoo代碼準(zhǔn)守PEP8,但忽略一些規(guī)則:E501:行太長(zhǎng)E301:預(yù)計(jì)有1個(gè)空行,找到0E302:預(yù)計(jì)有2個(gè)空行,找到1E126:延長(zhǎng)線過(guò)度縮進(jìn)用于懸掛縮進(jìn)E123:關(guān)閉支架與開(kāi)口支架線的壓痕不匹配E127:延伸線過(guò)度縮進(jìn)以進(jìn)行視覺(jué)縮進(jìn)E128:用于視覺(jué)縮進(jìn)延續(xù)線E265:阻評(píng)論應(yīng)以'#'開(kāi)頭import 順序外部庫(kù)導(dǎo)入odoo導(dǎo)入odoo模塊每組導(dǎo)入按字母順序# 1 : 導(dǎo)入python庫(kù)import base64import reimport timefrom datetime import datetime# 2 : imports of odooimport odoofrom odoo import api, fields, models # alphabetically orderedfrom odoo.tools.safe_eval import safe_eval as evalfrom odoo.tools.translate import _# 3 : imports from odoo modulesfrom odoo.addons.website.models.website import slugfrom odoo.addons.web.controllers.main import login_redirect編程習(xí)慣python文件以 # -*- coding: utf-8 -*- 為第一行易讀代碼Odoo中編程避免建生成器和裝飾器:僅用Odoo API已有用filtered,mapped,sorted方法提升代碼可讀性和性能用更易理解方法名讓你方法可批量處理添加函數(shù)時(shí),確??商幚矶鄶?shù)據(jù),如api.multi()裝飾器,可在self循環(huán)處理@api.multidef my_method(self)for record in self:record.do_cool_stuff()避免用api.one裝飾器,不像想象一樣工作。 為了性能,如定義狀態(tài)按鈕,不在api.multi循環(huán)用search和search_count方法,用read_group一次計(jì)算@api.multidef _compute_equipment_count(self):""" Count the number of equipement per category """equipment_data = self.env['hr.equipment'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in equipment_data])for category in self:category.equipment_count = mapped_data.get(category.id, 0)上下文環(huán)境 新API中,context變量不能修改。通過(guò)with_context用新運(yùn)行環(huán)境調(diào)用方法。records.with_context(new_context).do_stuff() # all the context is replacedrecords.with_context(**additionnal_context).do_other_stuff() # additionnal_context values override native context ones盡量用ORM當(dāng)ORM可實(shí)現(xiàn)時(shí)盡量用ORM而不直接寫(xiě)sql,因?yàn)闀?huì)繞過(guò)orm規(guī)則如權(quán)限、事務(wù)等,讓代碼變得難讀且不安全。# 錯(cuò)誤的寫(xiě)法,注入風(fēng)險(xiǎn),代碼效率低self.env.cr.execute('SELECT id FROM auction_lots WHERE auction_id in (' + ','.join(map(str, ids))+') AND state=%s AND obj_price > 0', ('draft',))auction_lots_ids = [x[0] for x in self.env.cr.fetchall()]# 不會(huì)被注入,但仍然是錯(cuò)誤的寫(xiě)法self.env.cr.execute('SELECT id FROM auction_lots WHERE auction_id in %s '\'AND state=%s AND obj_price > 0', (tuple(ids), 'draft',))auction_lots_ids = [x[0] for x in self.env.cr.fetchall()]# 推薦的寫(xiě)法auction_lots_ids = self.search([('auction_id','in',ids), ('state','=','draft'), ('obj_price','>',0)])防止注入不用python+號(hào)連接符、%解釋符拼sql# 錯(cuò)誤的寫(xiě)法self.env.cr.execute('SELECT distinct child_id FROM account_account_consol_rel ' +'WHERE parent_id IN ('+','.join(map(str, ids))+')')# 推薦的寫(xiě)法self.env.cr.execute('SELECT DISTINCT child_id '\'FROM account_account_consol_rel '\'WHERE parent_id IN %s',(tuple(ids),))正確用翻譯方法odoo用下劃線方法表明某字段需翻譯,通過(guò)from odoo.tools.translate import _導(dǎo)入。該方法只用在代碼里規(guī)定字符串翻譯,不用于動(dòng)態(tài)字符串翻譯,翻譯方法調(diào)用只能是_('literal string'),里面不能加其他的。# 好的方式,簡(jiǎn)潔error = _('This record is locked!')# 好的方式,包含格式的字符串error = _('Record %s cannot be modified!') % record# 好的方式,多行文字的字符串error = _("""This is a bad multiline exampleabout record %s!""") % recorderror = _('Record %s cannot be modified' \'after being validated!') % record# 錯(cuò)誤的方式:試圖在字符串格式化后進(jìn)行翻譯# 這樣沒(méi)有作用,而只會(huì)把翻譯搞亂error = _('Record %s cannot be modified!' % record)# 錯(cuò)誤:動(dòng)態(tài)字符串,不能這樣翻譯error = _("'" + que_rec['question'] + "' \n")# 錯(cuò)誤:字段值將會(huì)被系統(tǒng)字段翻譯,而不會(huì)獲取預(yù)期結(jié)果error = _("Product %s is out of stock!") % _(product.name)# 錯(cuò)誤的方式:試圖在字符串格式化后進(jìn)行翻譯error = _("Product %s is out of stock!" % product.name)符號(hào)和習(xí)慣模型名-用.分隔,模塊名做前綴定義odoo模型,用單數(shù)形式如res.user,res.partner定義wizard,命名格式.,related_base_model關(guān)聯(lián)模型名,action功能簡(jiǎn)稱(chēng),如account.invoice.make定義報(bào)表模型,用.report.,和wizard一樣python類(lèi)-用駝峰命名方式class AccountInvoice(models.Model):...class account_invoice(osv.osv):...變量名模型變量用駝峰命名普通變量用下劃線+小寫(xiě)字母新api中記錄是集合形式,當(dāng)變量不含id時(shí)不以id作后綴ResPartner = self.env['res.partner']partners = ResPartner.browse(ids)partner_id = partners[0].idOne2Many, Many2Many字段以ids作后綴如:sale_order_line_ids Many2One 以_id為后綴如:partner_id, user_id方法命名計(jì)算字段 - 計(jì)算方法_compute_搜索方法 - _search_默認(rèn)方法 - _default_onchange方法 - _onchange_約束方法 - _check_action方法 - 對(duì)象動(dòng)作方法以action_開(kāi)頭,裝飾器@api.multi,如只用單條計(jì)算,可在方法頭添加self.ensure_one()模型中屬性順序私有屬性:_name, _description, _inherit, ...默認(rèn)方法和_default_get字段聲明計(jì)算和搜索方法和字段聲明順序一致約束方法(@api.constrains)和onchange方法(@api.onchange)CRUD方法action方法其他業(yè)務(wù)方法class Event(models.Model):# 私有屬性_name = 'event.event'_description = 'Event'# 默認(rèn)方法def _default_name(self):...# 字段聲明name = fields.Char(string='Name', default=_default_name)seats_reserved = fields.Integer(oldname='register_current', string='Reserved Seats',store=True, readonly=True, compute='_compute_seats')seats_available = fields.Integer(oldname='register_avail', string='Available Seats',store=True, readonly=True, compute='_compute_seats')price = fields.Integer(string='Price')# 計(jì)算和搜索方法,與字段申明順序一致@api.multi@api.depends('seats_max', 'registration_ids.state', 'registration_ids.nb_register')def _compute_seats(self):...# 約束方法和onchange方法@api.constrains('seats_max', 'seats_available')def _check_seats_limit(self):...@api.onchange('date_begin')def _onchange_date_begin(self):...# CRUD方法 @api.modeldef create(self, values):...# action方法@api.multidef action_validate(self):self.ensure_one()...# 其他業(yè)務(wù)方法def mail_user_confirm(self):...Javascript和CSSjavascript文件用use strict;用linter不添加壓縮javascript庫(kù)類(lèi)名用駝峰命名javascript代碼需全局運(yùn)行,website模塊中聲明if_dom_contains 方法odoo.website.if_dom_contains('.jquery_class_selector', function () {/*your code here*/});class命名為o_,如o_forum避免用id用bootstrap的class用下劃線+小寫(xiě)命名# 錯(cuò)誤的寫(xiě)法self.env.cr.execute('SELECT distinct child_id FROM account_account_consol_rel ' +'WHERE parent_id IN ('+','.join(map(str, ids))+')')# 推薦的寫(xiě)法self.env.cr.execute('SELECT DISTINCT child_id '\'FROM account_account_consol_rel '\'WHERE parent_id IN %s',(tuple(ids),))開(kāi)發(fā)相關(guān)教程odoo 開(kāi)發(fā)技術(shù)棧,成為高級(jí)odoo開(kāi)發(fā)基本技能要求,開(kāi)發(fā)框架用pycharm搭建odoo 17,16,15,14, 13,12, 11,10 開(kāi)發(fā)調(diào)試環(huán)境,下載綠色版64位odoo更快更簡(jiǎn)單odoo17 免費(fèi)常用及高級(jí)widget大全,社區(qū)及企業(yè)版共計(jì)100+odoo17,16,15,14,13,12,11,10 實(shí)現(xiàn)多級(jí)樹(shù)狀視圖,前端開(kāi)發(fā)實(shí)例教程,引入ztree.jsodoo官方開(kāi)發(fā)教程,狠狠看,狠狠寫(xiě)代碼!odoo敏捷開(kāi)發(fā)-代碼生成器一鍵生成模塊聯(lián)系方式手機(jī):13822161573 微信:txsolarterms QQ:419396409柚子快報(bào)激活碼778899分享:Odoo代碼規(guī)范http://yzkb.51969.com/推薦鏈接評(píng)論可見(jiàn),查看隱藏內(nèi)容
id="model_name_menu_root"
name="Main Menu"
sequence="5"
/>
id="model_name_menu_action"name="Sub Menu 1"parent="module_name.module_name_menu_root"action="model_name_action"sequence="10"/>...............注意視圖名(name)用點(diǎn)表示法:my.model.view_type 或者my.model.view_type.inherit繼承XML命名繼承視圖命名規(guī)則:_inherit_,其中_inherit_是擴(kuò)展視圖模塊技術(shù)名稱(chēng)。...PythonOdoo代碼準(zhǔn)守PEP8,但忽略一些規(guī)則:E501:行太長(zhǎng)E301:預(yù)計(jì)有1個(gè)空行,找到0E302:預(yù)計(jì)有2個(gè)空行,找到1E126:延長(zhǎng)線過(guò)度縮進(jìn)用于懸掛縮進(jìn)E123:關(guān)閉支架與開(kāi)口支架線的壓痕不匹配E127:延伸線過(guò)度縮進(jìn)以進(jìn)行視覺(jué)縮進(jìn)E128:用于視覺(jué)縮進(jìn)延續(xù)線E265:阻評(píng)論應(yīng)以'#'開(kāi)頭import 順序外部庫(kù)導(dǎo)入odoo導(dǎo)入odoo模塊每組導(dǎo)入按字母順序# 1 : 導(dǎo)入python庫(kù)import base64import reimport timefrom datetime import datetime# 2 : imports of odooimport odoofrom odoo import api, fields, models # alphabetically orderedfrom odoo.tools.safe_eval import safe_eval as evalfrom odoo.tools.translate import _# 3 : imports from odoo modulesfrom odoo.addons.website.models.website import slugfrom odoo.addons.web.controllers.main import login_redirect編程習(xí)慣python文件以 # -*- coding: utf-8 -*- 為第一行易讀代碼Odoo中編程避免建生成器和裝飾器:僅用Odoo API已有用filtered,mapped,sorted方法提升代碼可讀性和性能用更易理解方法名讓你方法可批量處理添加函數(shù)時(shí),確??商幚矶鄶?shù)據(jù),如api.multi()裝飾器,可在self循環(huán)處理@api.multidef my_method(self)for record in self:record.do_cool_stuff()避免用api.one裝飾器,不像想象一樣工作。 為了性能,如定義狀態(tài)按鈕,不在api.multi循環(huán)用search和search_count方法,用read_group一次計(jì)算@api.multidef _compute_equipment_count(self):""" Count the number of equipement per category """equipment_data = self.env['hr.equipment'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in equipment_data])for category in self:category.equipment_count = mapped_data.get(category.id, 0)上下文環(huán)境 新API中,context變量不能修改。通過(guò)with_context用新運(yùn)行環(huán)境調(diào)用方法。records.with_context(new_context).do_stuff() # all the context is replacedrecords.with_context(**additionnal_context).do_other_stuff() # additionnal_context values override native context ones盡量用ORM當(dāng)ORM可實(shí)現(xiàn)時(shí)盡量用ORM而不直接寫(xiě)sql,因?yàn)闀?huì)繞過(guò)orm規(guī)則如權(quán)限、事務(wù)等,讓代碼變得難讀且不安全。# 錯(cuò)誤的寫(xiě)法,注入風(fēng)險(xiǎn),代碼效率低self.env.cr.execute('SELECT id FROM auction_lots WHERE auction_id in (' + ','.join(map(str, ids))+') AND state=%s AND obj_price > 0', ('draft',))auction_lots_ids = [x[0] for x in self.env.cr.fetchall()]# 不會(huì)被注入,但仍然是錯(cuò)誤的寫(xiě)法self.env.cr.execute('SELECT id FROM auction_lots WHERE auction_id in %s '\'AND state=%s AND obj_price > 0', (tuple(ids), 'draft',))auction_lots_ids = [x[0] for x in self.env.cr.fetchall()]# 推薦的寫(xiě)法auction_lots_ids = self.search([('auction_id','in',ids), ('state','=','draft'), ('obj_price','>',0)])防止注入不用python+號(hào)連接符、%解釋符拼sql# 錯(cuò)誤的寫(xiě)法self.env.cr.execute('SELECT distinct child_id FROM account_account_consol_rel ' +'WHERE parent_id IN ('+','.join(map(str, ids))+')')# 推薦的寫(xiě)法self.env.cr.execute('SELECT DISTINCT child_id '\'FROM account_account_consol_rel '\'WHERE parent_id IN %s',(tuple(ids),))正確用翻譯方法odoo用下劃線方法表明某字段需翻譯,通過(guò)from odoo.tools.translate import _導(dǎo)入。該方法只用在代碼里規(guī)定字符串翻譯,不用于動(dòng)態(tài)字符串翻譯,翻譯方法調(diào)用只能是_('literal string'),里面不能加其他的。# 好的方式,簡(jiǎn)潔error = _('This record is locked!')# 好的方式,包含格式的字符串error = _('Record %s cannot be modified!') % record# 好的方式,多行文字的字符串error = _("""This is a bad multiline exampleabout record %s!""") % recorderror = _('Record %s cannot be modified' \'after being validated!') % record# 錯(cuò)誤的方式:試圖在字符串格式化后進(jìn)行翻譯# 這樣沒(méi)有作用,而只會(huì)把翻譯搞亂error = _('Record %s cannot be modified!' % record)# 錯(cuò)誤:動(dòng)態(tài)字符串,不能這樣翻譯error = _("'" + que_rec['question'] + "' \n")# 錯(cuò)誤:字段值將會(huì)被系統(tǒng)字段翻譯,而不會(huì)獲取預(yù)期結(jié)果error = _("Product %s is out of stock!") % _(product.name)# 錯(cuò)誤的方式:試圖在字符串格式化后進(jìn)行翻譯error = _("Product %s is out of stock!" % product.name)符號(hào)和習(xí)慣模型名-用.分隔,模塊名做前綴定義odoo模型,用單數(shù)形式如res.user,res.partner定義wizard,命名格式.,related_base_model關(guān)聯(lián)模型名,action功能簡(jiǎn)稱(chēng),如account.invoice.make定義報(bào)表模型,用.report.,和wizard一樣python類(lèi)-用駝峰命名方式class AccountInvoice(models.Model):...class account_invoice(osv.osv):...變量名模型變量用駝峰命名普通變量用下劃線+小寫(xiě)字母新api中記錄是集合形式,當(dāng)變量不含id時(shí)不以id作后綴ResPartner = self.env['res.partner']partners = ResPartner.browse(ids)partner_id = partners[0].idOne2Many, Many2Many字段以ids作后綴如:sale_order_line_ids Many2One 以_id為后綴如:partner_id, user_id方法命名計(jì)算字段 - 計(jì)算方法_compute_搜索方法 - _search_默認(rèn)方法 - _default_onchange方法 - _onchange_約束方法 - _check_action方法 - 對(duì)象動(dòng)作方法以action_開(kāi)頭,裝飾器@api.multi,如只用單條計(jì)算,可在方法頭添加self.ensure_one()模型中屬性順序私有屬性:_name, _description, _inherit, ...默認(rèn)方法和_default_get字段聲明計(jì)算和搜索方法和字段聲明順序一致約束方法(@api.constrains)和onchange方法(@api.onchange)CRUD方法action方法其他業(yè)務(wù)方法class Event(models.Model):# 私有屬性_name = 'event.event'_description = 'Event'# 默認(rèn)方法def _default_name(self):...# 字段聲明name = fields.Char(string='Name', default=_default_name)seats_reserved = fields.Integer(oldname='register_current', string='Reserved Seats',store=True, readonly=True, compute='_compute_seats')seats_available = fields.Integer(oldname='register_avail', string='Available Seats',store=True, readonly=True, compute='_compute_seats')price = fields.Integer(string='Price')# 計(jì)算和搜索方法,與字段申明順序一致@api.multi@api.depends('seats_max', 'registration_ids.state', 'registration_ids.nb_register')def _compute_seats(self):...# 約束方法和onchange方法@api.constrains('seats_max', 'seats_available')def _check_seats_limit(self):...@api.onchange('date_begin')def _onchange_date_begin(self):...# CRUD方法 @api.modeldef create(self, values):...# action方法@api.multidef action_validate(self):self.ensure_one()...# 其他業(yè)務(wù)方法def mail_user_confirm(self):...Javascript和CSSjavascript文件用use strict;用linter不添加壓縮javascript庫(kù)類(lèi)名用駝峰命名javascript代碼需全局運(yùn)行,website模塊中聲明if_dom_contains 方法odoo.website.if_dom_contains('.jquery_class_selector', function () {/*your code here*/});class命名為o_,如o_forum避免用id用bootstrap的class用下劃線+小寫(xiě)命名# 錯(cuò)誤的寫(xiě)法self.env.cr.execute('SELECT distinct child_id FROM account_account_consol_rel ' +'WHERE parent_id IN ('+','.join(map(str, ids))+')')# 推薦的寫(xiě)法self.env.cr.execute('SELECT DISTINCT child_id '\'FROM account_account_consol_rel '\'WHERE parent_id IN %s',(tuple(ids),))開(kāi)發(fā)相關(guān)教程odoo 開(kāi)發(fā)技術(shù)棧,成為高級(jí)odoo開(kāi)發(fā)基本技能要求,開(kāi)發(fā)框架用pycharm搭建odoo 17,16,15,14, 13,12, 11,10 開(kāi)發(fā)調(diào)試環(huán)境,下載綠色版64位odoo更快更簡(jiǎn)單odoo17 免費(fèi)常用及高級(jí)widget大全,社區(qū)及企業(yè)版共計(jì)100+odoo17,16,15,14,13,12,11,10 實(shí)現(xiàn)多級(jí)樹(shù)狀視圖,前端開(kāi)發(fā)實(shí)例教程,引入ztree.jsodoo官方開(kāi)發(fā)教程,狠狠看,狠狠寫(xiě)代碼!odoo敏捷開(kāi)發(fā)-代碼生成器一鍵生成模塊聯(lián)系方式手機(jī):13822161573 微信:txsolarterms QQ:419396409柚子快報(bào)激活碼778899分享:Odoo代碼規(guī)范http://yzkb.51969.com/推薦鏈接評(píng)論可見(jiàn),查看隱藏內(nèi)容
id="model_name_menu_action"
name="Sub Menu 1"
parent="module_name.module_name_menu_root"
action="model_name_action"
sequence="10"
注意
視圖名(name)用點(diǎn)表示法:my.model.view_type 或者my.model.view_type.inherit
繼承XML命名
繼承視圖命名規(guī)則:_inherit_,其中_inherit_是擴(kuò)展視圖模塊技術(shù)名稱(chēng)。
Python
Odoo代碼準(zhǔn)守PEP8,但忽略一些規(guī)則:
E501:行太長(zhǎng)E301:預(yù)計(jì)有1個(gè)空行,找到0E302:預(yù)計(jì)有2個(gè)空行,找到1E126:延長(zhǎng)線過(guò)度縮進(jìn)用于懸掛縮進(jìn)E123:關(guān)閉支架與開(kāi)口支架線的壓痕不匹配E127:延伸線過(guò)度縮進(jìn)以進(jìn)行視覺(jué)縮進(jìn)E128:用于視覺(jué)縮進(jìn)延續(xù)線E265:阻評(píng)論應(yīng)以'#'開(kāi)頭
import 順序
外部庫(kù)導(dǎo)入odoo導(dǎo)入odoo模塊
每組導(dǎo)入按字母順序
# 1 : 導(dǎo)入python庫(kù)
import base64
import re
import time
from datetime import datetime
# 2 : imports of odoo
import odoo
from odoo import api, fields, models # alphabetically ordered
from odoo.tools.safe_eval import safe_eval as eval
from odoo.tools.translate import _
# 3 : imports from odoo modules
from odoo.addons.website.models.website import slug
from odoo.addons.web.controllers.main import login_redirect
編程習(xí)慣
python文件以 # -*- coding: utf-8 -*- 為第一行易讀代碼
Odoo中編程
避免建生成器和裝飾器:僅用Odoo API已有用filtered,mapped,sorted方法提升代碼可讀性和性能用更易理解方法名
讓你方法可批量處理
添加函數(shù)時(shí),確??商幚矶鄶?shù)據(jù),如api.multi()裝飾器,可在self循環(huán)處理
@api.multi
def my_method(self)
for record in self:
record.do_cool_stuff()
避免用api.one裝飾器,不像想象一樣工作。 為了性能,如定義狀態(tài)按鈕,不在api.multi循環(huán)用search和search_count方法,用read_group一次計(jì)算
def _compute_equipment_count(self):
""" Count the number of equipement per category """
equipment_data = self.env['hr.equipment'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])
mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in equipment_data])
for category in self:
category.equipment_count = mapped_data.get(category.id, 0)
上下文環(huán)境 新API中,context變量不能修改。通過(guò)with_context用新運(yùn)行環(huán)境調(diào)用方法。
records.with_context(new_context).do_stuff() # all the context is replaced
records.with_context(**additionnal_context).do_other_stuff() # additionnal_context values override native context ones
盡量用ORM
當(dāng)ORM可實(shí)現(xiàn)時(shí)盡量用ORM而不直接寫(xiě)sql,因?yàn)闀?huì)繞過(guò)orm規(guī)則如權(quán)限、事務(wù)等,讓代碼變得難讀且不安全。
# 錯(cuò)誤的寫(xiě)法,注入風(fēng)險(xiǎn),代碼效率低
self.env.cr.execute('SELECT id FROM auction_lots WHERE auction_id in (' + ','.join(map(str, ids))+') AND state=%s AND obj_price > 0', ('draft',))
auction_lots_ids = [x[0] for x in self.env.cr.fetchall()]
# 不會(huì)被注入,但仍然是錯(cuò)誤的寫(xiě)法
self.env.cr.execute('SELECT id FROM auction_lots WHERE auction_id in %s '\
'AND state=%s AND obj_price > 0', (tuple(ids), 'draft',))
# 推薦的寫(xiě)法
auction_lots_ids = self.search([('auction_id','in',ids), ('state','=','draft'), ('obj_price','>',0)])
防止注入
不用python+號(hào)連接符、%解釋符拼sql
# 錯(cuò)誤的寫(xiě)法
self.env.cr.execute('SELECT distinct child_id FROM account_account_consol_rel ' +
'WHERE parent_id IN ('+','.join(map(str, ids))+')')
self.env.cr.execute('SELECT DISTINCT child_id '\
'FROM account_account_consol_rel '\
'WHERE parent_id IN %s',
(tuple(ids),))
正確用翻譯方法
odoo用下劃線方法表明某字段需翻譯,通過(guò)from odoo.tools.translate import _導(dǎo)入。該方法只用在代碼里規(guī)定字符串翻譯,不用于動(dòng)態(tài)字符串翻譯,翻譯方法調(diào)用只能是_('literal string'),里面不能加其他的。
# 好的方式,簡(jiǎn)潔
error = _('This record is locked!')
# 好的方式,包含格式的字符串
error = _('Record %s cannot be modified!') % record
# 好的方式,多行文字的字符串
error = _("""This is a bad multiline example
about record %s!""") % record
error = _('Record %s cannot be modified' \
'after being validated!') % record
# 錯(cuò)誤的方式:試圖在字符串格式化后進(jìn)行翻譯
# 這樣沒(méi)有作用,而只會(huì)把翻譯搞亂
error = _('Record %s cannot be modified!' % record)
# 錯(cuò)誤:動(dòng)態(tài)字符串,不能這樣翻譯
error = _("'" + que_rec['question'] + "' \n")
# 錯(cuò)誤:字段值將會(huì)被系統(tǒng)字段翻譯,而不會(huì)獲取預(yù)期結(jié)果
error = _("Product %s is out of stock!") % _(product.name)
error = _("Product %s is out of stock!" % product.name)
符號(hào)和習(xí)慣
模型名-用.分隔,模塊名做前綴定義odoo模型,用單數(shù)形式如res.user,res.partner定義wizard,命名格式.,related_base_model關(guān)聯(lián)模型名,action功能簡(jiǎn)稱(chēng),如account.invoice.make定義報(bào)表模型,用.report.,和wizard一樣python類(lèi)-用駝峰命名方式
class AccountInvoice(models.Model):
class account_invoice(osv.osv):
變量名
模型變量用駝峰命名普通變量用下劃線+小寫(xiě)字母新api中記錄是集合形式,當(dāng)變量不含id時(shí)不以id作后綴
ResPartner = self.env['res.partner']
partners = ResPartner.browse(ids)
partner_id = partners[0].id
One2Many, Many2Many字段以ids作后綴如:sale_order_line_ids Many2One 以_id為后綴如:partner_id, user_id
方法命名
計(jì)算字段 - 計(jì)算方法_compute_搜索方法 - _search_默認(rèn)方法 - _default_onchange方法 - _onchange_約束方法 - _check_
action方法 - 對(duì)象動(dòng)作方法以action_開(kāi)頭,裝飾器@api.multi,如只用單條計(jì)算,可在方法頭添加self.ensure_one()
模型中屬性順序
私有屬性:_name, _description, _inherit, ...默認(rèn)方法和_default_get字段聲明計(jì)算和搜索方法和字段聲明順序一致約束方法(@api.constrains)和onchange方法(@api.onchange)CRUD方法action方法其他業(yè)務(wù)方法
class Event(models.Model):
# 私有屬性
_name = 'event.event'
_description = 'Event'
# 默認(rèn)方法
def _default_name(self):
# 字段聲明
name = fields.Char(string='Name', default=_default_name)
seats_reserved = fields.Integer(oldname='register_current', string='Reserved Seats',
store=True, readonly=True, compute='_compute_seats')
seats_available = fields.Integer(oldname='register_avail', string='Available Seats',
price = fields.Integer(string='Price')
# 計(jì)算和搜索方法,與字段申明順序一致
@api.depends('seats_max', 'registration_ids.state', 'registration_ids.nb_register')
def _compute_seats(self):
# 約束方法和onchange方法
@api.constrains('seats_max', 'seats_available')
def _check_seats_limit(self):
@api.onchange('date_begin')
def _onchange_date_begin(self):
# CRUD方法 @api.model
def create(self, values):
# action方法
def action_validate(self):
self.ensure_one()
# 其他業(yè)務(wù)方法
def mail_user_confirm(self):
Javascript和CSS
javascript文件用use strict;用linter不添加壓縮javascript庫(kù)類(lèi)名用駝峰命名javascript代碼需全局運(yùn)行,website模塊中聲明if_dom_contains 方法
odoo.website.if_dom_contains('.jquery_class_selector', function () {
/*your code here*/
});
class命名為o_,如o_forum避免用id用bootstrap的class用下劃線+小寫(xiě)命名
開(kāi)發(fā)相關(guān)教程
odoo 開(kāi)發(fā)技術(shù)棧,成為高級(jí)odoo開(kāi)發(fā)基本技能要求,開(kāi)發(fā)框架用pycharm搭建odoo 17,16,15,14, 13,12, 11,10 開(kāi)發(fā)調(diào)試環(huán)境,下載綠色版64位odoo更快更簡(jiǎn)單odoo17 免費(fèi)常用及高級(jí)widget大全,社區(qū)及企業(yè)版共計(jì)100+odoo17,16,15,14,13,12,11,10 實(shí)現(xiàn)多級(jí)樹(shù)狀視圖,前端開(kāi)發(fā)實(shí)例教程,引入ztree.jsodoo官方開(kāi)發(fā)教程,狠狠看,狠狠寫(xiě)代碼!odoo敏捷開(kāi)發(fā)-代碼生成器一鍵生成模塊
聯(lián)系方式
手機(jī):13822161573 微信:txsolarterms QQ:419396409
推薦鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。
本文鏈接:http://gantiao.com.cn/post/19193721.html
取消回復(fù)
請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳
掃描二維碼手機(jī)訪問(wèn)