* 官方建议模块骨架
--------------------------
addons/<my_module_name>/
│─ __init__.py
│- __openerp__.py
│- controllers
│ │- __init__.py
│ │- main.py
│- data
│ │- <main_model>_data.xml
│ │- <inherited_main_model>_demo.xml

│- models
│ │- __init__.py
│ │- <main_model>.py
│ │- <inherited_main_model>.py

│- security
│ │- ir.model.access.csv 
│ │- <main_model>_security.xml

│- static
│ │- img
│ │- lib
│ │- src
│ │ │- js
│ │ │- css
│ │ │- less
│ │ │- xml
│- views
│ │- <main_model>_templates.xml
│ │- <main_model>_views.xml 

文件夹权限755 文件权限644
__openerp__.py 相关属性:
# name 模块名字
# summary 简短介绍
# description 详细描述
# author 作者
# website 模块网站
# category 模块分类
# version 模块版本号
# license 模块版本信息 默认是 AGPL-3
# depends 模块依赖
# data 模块必须加载的数据文件
# demo 示例数据
# installabel 默认为True 可安装
# auto_install 默认是False 如果设为True 就根据依赖模块,依赖装了,这个模块就安装
# application 默认是 False 如果设为True 就成为应用模块

安装自定义模块
服务启动配置文件 addons-path 加入自己的定义容器目录 如 myaddons
addons-path=addons,myaddons
更新模块服务列表,然后找到去安装

模块文件夹管理
# data 放 demo 和 data xml
# models 放模型定义
# controllers http 路径控制
# views 放网页视图和模板
# static 放网页的资源,里面还有css, js ,img, lib 等
#


--------------------------

todo_app
│ - security
│ | - ir.model.access.csv
│ | - todo_access_rules.xml
│ - static
│ - __init__.py
│ - __openerp__.py
│ - todo_model.py
│ - todo_view.xml

* __init__.py 内容如下(把模型导入到应用)

from . import todo_model


* __opererp__.py 内容如下(erp本身的配置)

--------------

{
'name':'To-Do Application',
'description': 'Manage your personal Tasks with this module.',
'author': 'Toby Chen',
'depends': ['mail'],
'application': True,
'category':'todo_app',
'data': [
'todo_view.xml',
'security/ir.model.access.csv',
'security/todo_access_rules.xml',
],
}

--------------

* todo_model.py 内容如下(模型)

--------------
# -*- coding: utf-8 -*-
from openerp import models,fields,api

class TodoTask(models.Model):
_name='todo.task'
name = fields.Char('Description', required=True)
is_done = fields.Boolean('Done?')
active = fields.Boolean('Active?', default=True)

@api.one
def do_toggle_done(self):
self.is_done = not self.is_done
return True

@api.multi
def do_clear_done(self):
done_recs = self.search([('is_done','=','True')])
done_recs.write({'active':False})
return True
--------------

* todo_view.xml内容如下(视图)

--------------
<?xml version="1.0" encoding="utf-8" ?>
<openerp>
<data>
<act_window id="action_todo_task"
name="To-do Task"
res_model="todo.task"
view_mode="tree,form" />

<menuitem id="menu_todo_task"
name="To-Do Task"
parent="mail.mail_feeds"
sequence="20"
action="action_todo_task" />

<record id="view_form_todo_task" model="ir.ui.view">
<field name="name">To-do Task Form</field>
<field name="model">todo.task</field>
<field name="arch" type="xml">
<form string="To-do Task">
<header>
<button name="do_toggle_done" type="object"
string="Toggle Done" class="oe_highlight"/>
<button name="do_clear_done" type="object"
string="Clear All Done"/>
</header>
<sheet>
<group name="group_top">
<group name="group_left">
<field name="name"/>
</group>
<group name="group_right">
<field name="is_done"/>
<field name="active" readonly="1"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_tree_todo_task" model="ir.ui.view">
<field name="name">To-do Task Tree</field>
<field name="model">todo.task</field>
<field name="arch" type="xml">
<tree colors="gray:is_done==True">
<field name="name"/>
<field name="is_done"/>
</tree>
</field>
</record>

<record id="view_filter_todo_task" model="ir.ui.view">
<field name="name">To-do Task Filter</field>
<field name="model">todo.task</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<filter string="Not Done"
domain="[('is_done','=',False)]"/>
<filter string="Done"
domain="[('is_done','!=',False)]"/>
</search>
</field>
</record>
</data>

</openerp>
--------------

* ir.model.access.csv 内容如下()
-------------------
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_todo_task_group_user,todo.task.user,model_todo_task,base.group_user,1,1,1,1
-------------------

* todo_access_rules.xml
-----------------
<?xml version="1.0" encoding="UTF-8" ?>
<openerp>
<data noupdate="1">
<record id="todo_task_user_rule" model="ir.rule">
<field name="name">ToDo Tasks only for owner</field>
<field name="model_id" ref="model_todo_task"/>
<field name="domain_force">[('create_uid','=',user.id)]
</field>
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
</record>
</data>
</openerp>
-----------------


* 可以到系统的本地模块中找到 去安装

* 开服务时要以升级模块
./odoo.py -d v8dev -u todo_app 用模块的目录

* 升级完,最好重启一下odoo的服务,不容易报错

====================================
再来一小段

模型
class Fruit(models.Model):
_name = 'mymodule.fruits'
name = fields.Char()

加一个演示数据 demo.xml
<openerp>
<data>
<record id=”apple” model=”mymodule.fruits”>
<field name=”name”>apple</field>
</record>
<record id=”banana” model=”mymodule.fruits”>
<field name=”name”>banana</field>
</record>
<record id=”pear” model=”mymodule.fruits”>
<field name=”name”>pear</field>
</record>
</data>
</openerp>

看一下控制器
from openerp import http

class Mymodule(http.Controller)
@http.route('/mymodule/mymodule',auth='public')
def index(self,**kw)
fruits = http.request.env('mymodule.fruits')
return http.request.render("mymodule.index",{'fruits':fruits.search([])})

视图
<openerp>
<data>
<template id='index'>
<title>MyModule</title>
<t t-foreach="fruits" t-as="fruit">
<p><t t-esc="fruit.id" /><t t-esc="fruit.name" /></p>
</t>
</template>
</data>
</openerp>

上面的页面展示只有数据,不好看,可以用 website builder模块美化
__openerp__.py 加上
'depends':['website']

控制器加上
@http.route('/mymodule/mymodule', auth='public' website=True)

视图文件修改
<openerp>
<data>
<template id=”index”>
<t t-call=”website.layout”>
<t t-set=”title”>MyModule</t>
<div class=”oe_structure”>
<div class=”container”>
<t t-foreach=”fruits” t-as=”fruit”>
<p><t t-esc=”fruit.id”/><t t-esc=”fruit.name”></t></p>
</t>
</div>
</div>
</t>
</template>
</data>
</openerp>

采用了 t-call 调用标准模板 用 t-set 设置属性值 加了oe_structrue 和 container 类