Odoo(OpenERP)开发规范(持续完善中)
转自:http://blog.sina.com.cn/s/blog_729a47890102vov3.html
Modules(模块)
-
模块命名使用单数形式 (或者使用 "multi"), 除非模块有多个功能模块组成,或者系统中已经存在。
-
使用描述模板,可以移除无意义的内容U
-
__openerp__.py文件注意事项:-
避免使用空格
-
确定含版权项
-
确定远鼎 openerp@chinamaker.net已经追加到描述信息
-
Directories(目录)
一个模块一般由几个目录组成
-
controllers/: contains controllers (http routes) -
data/: data xml -
demo/: demo xml -
models/: models definition -
report/: reporting models (BI/analysis), Webkit/RML print report templates -
static/: contains the web assets, separated intocss/,js/,img/,lib/, ... -
views/: contains the views and templates, and QWeb report print templates -
wizards/: wizard model and views
File naming(文件命名)
对于模型,视图和数据声明,分割文件所涉及的模型,创建或继承。这些文件应该模型来命名。例如,演示数据res.partner应该在一个名demo/ res_partner.xml文件和伙伴视图应该在一个文件名为views/ res_partner.xml。
对于一个名为 的模块,以下文件可能创建:
-
models/.py -
data/.xml -
demo/.xml -
templates/.xml -
views/.xml
对于控制器,唯一的文件应该被命名为main.py.
对于静态文件,名称模式是<</span>模块> .ext(static/js / im_chat.js,static/ CSS / im_chat.css, static/ XML /
im_chat.xml,...)。不要链接外部数据(图像,库):复制到我们的代码库,而不是使用
URL。
整个模块的目录结构
addons//
|-- __init__.py
|-- __openerp__.py
|-- controllers/
| |-- __init__.py
| `-- main.py
|-- data/
| `-- .xml
|-- demo/
| `--
.xml
|-- models/
| |-- __init__.py
| |-- .py
| `--
.py
|-- report/
| |-- __init__.py
| |-- report.xml
| |--
.py
| |--
report_.rml
| |--
report_.py
| |--
.mako
|-- security/
| |--
ir.model.access.csv
| `--
_security.xml
|-- static/
| |-- img/
| | |--
my_little_kitten.png
| | `-- troll.jpg
| |-- lib/
| | `-- external_lib/
| `-- src/
| |-- js/
| | `--
.js
| |-- css/
| | `--
.css
| |-- less/
| | `--
.less
| `-- xml/
| `--
.xml
|-- views/
| |-- .xml
| `--
_views.xml
| |--
report_.xml
|-- templates/
| |-- .xml
| `--
.xml
`-- wizards/
|-- __init__.py
|-- .py
`-- .xml
文件名应该只仅使用[A-Z0-9_]
使用正确的文件权限:755文件夹和文件644。
XML files(XML文件)
Format(格式)
当声明一个 record 的时候
-
id属性放在model前面(后面举例说明) -
对于field 的声明,
首先定义name. 其次对value赋值(field或者evalattribute), 然后是其它属性,根据重要程度排序。 -
根据模型组织record组。在定义依赖的时候(在action/menu/views之间),本规则不适用。
-
使用命名规则定义下一个节点(point)
-
标签只在一种情况下使用: 设置 not-updatable
noupdate=1
view.name
object_name
Naming xml_id(xml_id 命名)
Security, View and Action
使用以下原则:
-
动作(action): 主action相关的以
_action命名.其它action 以_为后缀,detail是一个带下划线的字符串(解释动作的作用,不能太长)。 -
组(group):
_group_,group_name是group名称, 通常是'user', 'manager', ... -
规则(rule):
_rule_concerned_group相关用户组的短名称group ('user' for the 'model_name_group_user', 'public' for public user, 'company' for multi-company rules, ...).
...
...
...
...
...
...
...
...
Inherited XML(XML继承)
一个模块一次扩展一个视图一次。
XML继承视图的命名规则同普通视图。附带模块名可以防止xid冲突。
...
External dependencies(外部依赖)
__openerp__.py
如果模块使用了外部python代码 或者二进制文件,在 __openerp__.py需要说明。
{
'name': 'Example Module',
...
'external_dependencies': {
'bin': [
'external_dependency_binary_1',
'external_dependency_binary_2',
...
'external_dependency_binary_N',
],
'python': [
'external_dependency_python_1',
'external_dependency_python_2',
...
'external_dependency_python_N',
],
},
...
'installable': True,
}
二进制文件需要在PATH 环境变量下。
python 库需要在 PYTHONPATH 环境变量下。
ImportError(导入错误)
为了防止外部导入异常,导入外部 python文件时,请使用以下代码块。
try:
import external_dependency_python_N
except ImportError:
_logger.debug('Can not `import external_dependency_python_N`.')
README(说明)
如果你的模块依赖外部python文件或者二进制文件,请在README.rst说明依赖库或者文件如果安装。
Python(Python代码规范)
PEP8 options(PEP8规范)
项目应该坚持使用 PEP8规范,有助于查看格式和语法错误。也有例外:
-
In
__init__.pyonly-
F401:
moduleimported but unused
-
Imports(导入顺序)
Python 模块导入顺序
-
外部库Externals libs (一行一个库)
-
Imports of
openerp -
Imports from Odoo modules (rarely, and only if necessary)
-
Local imports in the relative form
出了这四种恰况,其它导入按字符排序。
# 1: imports of python lib
import base64
import re
import time
# 2: imports of openerp
import openerp
from openerp import api, fields, models # alphabetically ordered
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.translate import _
# 3: imports from odoo modules
from openerp.addons.website.models.website import slug
from openerp.addons.web.controllers.main import login_redirect
# 4: local imports
from . import utils
-
提示:
-
可以使用 isort对导入排序.
-
用pip install isort,然后isort myfile.py.
-
Idioms(风格)
-
每个 python 文件以
# -*- coding: utf-8 -*-作为第一行 -
Prefer
%over.format(), prefer%(varname)instead of positional. This is better for translation and clarity. -
Always favor Readability over conciseness or using the language features or idioms.
-
Use list comprehension, dict comprehension, and basic manipulation using
map,filter,sum, ... They make the code more pythonic, easier to read and are generally more efficient -
The same applies for recordset methods: use
filtered,mapped,sorted, ... -
Exceptions: Use
from openerp.exceptions import Warning as UserError(v8) orfrom openerp.exceptions import UserError(v9) or find a more appropriate exception inopenerp.exceptions.py -
Document your code
-
Docstring on methods should explain the purpose of a function, not a summary of the code
-
Simple comments for parts of code which do things which are not immediately obvious
-
Too many comments are usually a sign that the code is unreadable needs to be refactored
-
-
Use meaningful variable/class/method names
-
If a function is too long or too indented due to loops, this is a sign that it needs to be refactored into smaller functions
-
If a function call, dictionary, list or tuple is broken into two lines, break it at the opening symbol. This adds a four space indent to the next line instead of starting the next line at the opening symbol. Example:
python partner_id = fields.Many2one( "res.partner", "Partner", "Required", ) -
When making a comma separated list, dict, tuple, ... with one element per line, append a comma to the last element. This makes it so the next element added only changes one line in the changeset instead of changing the last element to simply add a comma.
-
If an argument to a function call is not immediately obvious, prefer using named parameter.
-
Use English variable names and write comments in english. Strings which need to be displayed in other languages should be translated using the translation system
Symbols(符号)
Odoo Python Class(Odoo python 类)
Use camelcase for code in api v8, underscore lowercase notation for old api.
class AccountInvoice(models.Model):
...
class account_invoice(orm.Model):
...
Variable name :
-
use underscore lowercase notation for common variable (snake_case)
-
since new API works with record or recordset instead of id list, don't suffix variable name with
_idor_idsif they do not contain an id or a list of ids.
...
res_partner = self.env['res.partner']
partners = res_partner.browse(ids)
partner_id = partners[0].id
-
Use underscore uppercase notation for global variables or constants
...
CONSTANT_VAR1 = 'Value'
...
class...
...
Field
-
One2ManyandMany2Manyfields should always have_idsas suffix (example: sale_order_line_ids) -
Many2Onefields should have_idas suffix (example: partner_id, user_id, ...) -
If the technical name of the field (the variable name) is the same to the string of the label, don't put
stringparameter for new API fields, because it's automatically taken. If your variable name contains "_" in the name, they are converted to spaces when creating the automatic string and each word is capitalized. (example: old api'name': fields.char('Name', ...)new api'name': fields.Char(...)) -
Method conventions
-
Compute Field: the compute method pattern is
_compute_ -
Search method: the search method pattern is
_search_ -
Default method: the default method pattern is
_default_ -
Onchange method: the onchange method pattern is
_onchange_ -
Constraint method: the constraint method pattern is
_check_ -
Action method: an object action method is prefix with
action_. Its decorator is@api.multi, but since it use only one record, addself.ensure_one()at the beginning of the method.
-
-
Default functions should be declared with a lambda call on self. The reason for this is so a default function can be inherited. Assigning a function pointer directly to the
defaultparameter does not allow for inheritance.a_field(..., default=lambda self: self._default_get()) -
In a Model attribute order should be
-
Private attributes (
_name,_description,_inherit, ...) -
Fields declarations
-
Default method and
_default_get -
Compute and search methods in the same order than field declaration
-
Constrains methods (
@api.constrains) and onchange methods (@api.onchange) -
CRUD methods (ORM overrides)
-
Action methods
-
And finally, other business methods.
-
class Event(models.Model):
# Private attributes
_name = 'event.event'
_description = 'Event'
# Fields declaration
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')
# Default methods
def _default_name(self):
...
# compute and search fields, in the same order that fields declaration
@api.multi
@api.depends('seats_max',
'registration_ids.state')
def _compute_seats(self):
...
# Constraints and onchanges
@api.constrains('seats_max',
'seats_available')
def _check_seats_limit(self):
...
@api.onchange('date_begin')
def _onchange_date_begin(self):
...
# CRUD methods
def create(self):
...
# Action methods
@api.multi
def action_validate(self):
self.ensure_one()
...
# Business methods
def mail_user_confirm(self):
...
Javascript
-
use strict;is recommended for all javascript files -
Use a linter (jshint, ...)
-
Never add minified Javascript Libraries
-
Use camelcase for class declaration
CSS
-
Prefix all your class with
o_wheremodule_nameis the technical name of the module (sale,im_chat, ...) or the main route reserved by the module (for website module mainly, i.e.o_forumfor website_forum module). The only exception for this rule is the webclient: it simply useo_prefix. -
Avoid using id
-
Use bootstrap native class
-
Use underscore lowercase notation to name class
Tests(测试)
As a general rule, a bug fix should come with a unittest which would fail without the fix itself. This is to assure that regression will not happen in the future. It also is a good way to show that the fix works in all cases.
New modules or addtions should ideally test all the functions defined. The coveralls utility will comment on pull requests indicating if coverage increased or decreased. If it has decreased, this is usually a sign that a test should be added. The coveralls web interface can also show which lines need test cases.
Git
Commit message
Write a short commit summary without prefixing it. It should not be longer than 50 characters: This is a commit message
Then, in the message itself, specify the part of the code impacted by your changes (module name, lib, transversal object, ...) and a description of the changes. This part should be multiple lines no longer than 80 characters.
-
Commit messages are in English
-
Merge proposals should follow the same rules as the title of the propsal is the first line of the merge commit and the description corresponds to commit description.
-
Always put meaning full commit message: commit message should be self explanatory (long enough) including the name of the module that has been changed and the reason behind that change. Do not use single words like "bugfix" or "improvements".
-
Avoid commits which simultaneously impacts lots of modules. Try to splits into different commits where impacted modules are different (It will be helpful when we are going to revert that module separately).
-
Only make a single commit per logical change set. Do not add commits such as "Fix pep8", "Code review" or "Add unittest" if they fix commits which are being proposed
-
Use present imperative (Fix formating, Remove unused field) avoid appending 's' to verbs: Fixes, Removes
website: remove unused
alert div
Fix look of
input-group-btn
Bootstrap's CSS depends on
the input-group-btn element being the first/last
child of its parent.
This
was not the case because of the invisible and useless alert.
web: add module system to
the web client
This commit introduces a
new module system for the javascript code.
Instead
of using global ...
Review
Peer review is the only way to ensure good quality of the code and to be able to rely on the others devs. The peer review in this project will be made by making Merge Proposal. It will serve the following main purposes:
-
Having a second look on his work to avoid unintended problems / bugs
-
Avoid technical or business design flaws
-
Allow the coordination and convergence of the devs by informing community of what has been done
-
Allow the responsibles to look at every devs and keep the interested people informed of what has been done
-
Prevent addons incompatibilities when/if possible
-
The rationale for peer review has its equivalent in Linus's law, often phrased: "Given enough eyeballs, all bugs are shallow"
Meaning "If there are enough reviewers, all problems are easy to solve". Eric S. Raymond has written influentially about peer review in software development: http://en.wikipedia.org/wiki/Software_peer_review.
Please respect a few basic rules:
-
Two reviewers must approve a merge proposal in order to be able to merge it
-
5 calendar days must be given to be able to merge it
-
A MP can be merged in less that 5 calendar days if and only if it is approved by 3 reviewers. If you are in a hurry just send a mail at openerp-community-reviewer@lists.launchpad.net or ask by IRC (FreeNode server, openobject channel).
-
Is the module generic enough to be part of community addons?
-
Is the module duplicating features with other community addons?
-
Does the documentation allow to understand what it does and how to use it?
-
Is the problem it tries to resolve adressed the good way, using good concepts?
-
Are there some use cases?
-
Is there any setup in code? Should not!
-
Are there demo data?
There are the following important part in a review:
-
Start by thanking the contributor / developer for his work. No matter the issue of the MP, someone make work for you here, so be thankful for that.
-
Be cordial and polite. Nothing is obvious in a MP.
-
The description of the changes should be clear enough for you to understand his purpose and if apply, contain the reference feature instance in order to allow people to run and test the review
-
Choose the review tag (comment, approve, rejected, needs information,...) and don't forget to add a type of review to let people know:
-
Code review: means you look at the code
-
Test: means you tested it functionally speaking
-
While making the merge, please respect the author using the --author option when committing. The author is found using the bzr log command. Use the commit message provided by the contributor if any.
It makes sense to be picky in the following cases:
-
The origin/reason for the patch/dev is not documented very well
-
No adapted / convenient description written in the
__openerp__.pyfile for the module -
Tests or scenario are not all green and/or not adapted
-
Having tests is very much encouraged
-
Issues with license, copyright, authorship
-
Respect of Odoo/community conventions
-
Code design and best practices
The long description try to explain the why not the what, the what can be seen in the diff.
Github
Teams
-
Team name must not contain odoo or openerp
-
Team name for localization is "Belgium Maintainers" for Belgium
Repositories
-
Project name must not contain odoo or openerp
-
Project name for localization is "l10n_belgium" for Belgium
-
Project name for connectors is "connector-magento" for Magento connector
Issue
-
Issues are used for blueprints and bugs.
浙公网安备 33010602011771号