> 警告
> 本教程需要已經安裝odoo
[TOC]
#### 啟動/停止Odoo服務器
Odoo采用C/S架構,客戶端通過Web瀏覽器訪問服務端,遵從RPC協議。業務邏輯和擴展通常在服務端執行,而只有添加客戶端支持的新特征才會在客戶端添加代碼(例如,交互過程中新數據的映射表示)。啟動服務器,只需要在shell中調用命令odoo-bin,或者完整的路徑名調用:
~~~
odoo-bin
~~~
通過`Ctrl-c`或殺死相應的系統進程來停止Odoo服務。
#### 構建一個Odoo模塊
服務端擴展和客戶端擴展都被封裝為模塊,這些模塊可選擇性的被安裝,安裝完成后通過數據庫來加載。模塊即可以是全新的業務邏輯,也可以是更改和擴展已有的業務邏輯。比如創建一個中國會計模塊,將中國的會計準則添加到Odoo的通用會計中,也可以創建一個全新的實時可視化管理車隊的模塊。Odoo中的所有功能都是包含在模塊中。
##### 模塊的組成
Odoo模塊包含多個部分:
**業務對象**
Python類,這些類會被Odoo框架自動持久化,持久化的方式決定于類的定義。
**數據文件**
包括視圖、菜單、動作、工作流、權限、演示數據等,以XML或CSV文件定義。
**Web控制器**
處理Web瀏覽器的請求
**靜態頁面數據**
網站或界面使用的圖片、CSS或JavaScript文件
##### 模塊結構
每個模塊都是模塊目錄中的一個子目錄。可以通過`--addons-path`選項指定模塊目錄的路徑。
> 提示
> 大多數命令行選項可以通過配置文件進行設置
Odoo模塊由清單文件進行聲明。查看清單文件文檔了解詳細信息。模塊是一個包含`__init__.py`文件的的Python包,`__init__.py`文件包含了模塊需要的導入的各Python文件。
例如,如果模塊中包含`mymodule.py`文件,`__init__.py`應該這樣寫:
~~~
from . import mymodule
~~~
Odoo提供了腳手架機制來快速創建新模塊,`odoo-bin`子命令`scaffold`用來創建一個空模塊
~~~
$ odoo-bin scaffold <模塊名> <模塊放置路徑>
~~~
該命令為模塊創建一個子目錄,并自動為模塊創建一些標準文件。這些文件大多只包含被注釋的代碼和XML元素。后面將解釋這些文件的含義。
> **練習創建模塊**
> 使用上面的命令行創建一個空模塊*Open Academy*,并將其安裝在Odoo中。
>
> 1. 調用命令`odoo-bin scaffold openacademy addons`
> 2. 修改模塊中的相關文件
> 3. 不要修改其它文件
`openacademy/__manifest__.py`
~~~
# -*- coding: utf-8 -*-
{
'name': "Open Academy",
'summary': """Manage trainings""",
'description': """
Open Academy module for managing trainings:
- training courses
- training sessions
- attendees registration
""",
'author': "My Company",
'website': "http://www.yourcompany.com",
# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
# for the full list
'category': 'Test',
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['base'],
# always loaded
'data': [
# 'security/ir.model.access.csv',
'templates.xml',
],
# only loaded in demonstration mode
'demo': [
'demo.xml',
],
}
~~~
`openacademy/__init__.py`
~~~
# -*- coding: utf-8 -*-
from . import controllers
from . import models
~~~
`openacademy/controllers.py`
~~~
# -*- coding: utf-8 -*-
from odoo import http
# class Openacademy(http.Controller):
# @http.route('/openacademy/openacademy/', auth='public')
# def index(self, **kw):
# return "Hello, world"
# @http.route('/openacademy/openacademy/objects/', auth='public')
# def list(self, **kw):
# return http.request.render('openacademy.listing', {
# 'root': '/openacademy/openacademy',
# 'objects': http.request.env['openacademy.openacademy'].search([]),
# })
# @http.route('/openacademy/openacademy/objects/<model("openacademy.openacademy"):obj>/', auth='public')
# def object(self, obj, **kw):
# return http.request.render('openacademy.object', {
# 'object': obj
# })
~~~
`openacademy/demo.xml`
~~~
<odoo>
<data>
<!-- -->
<!-- <record id="object0" model="openacademy.openacademy"> -->
<!-- <field name="name">Object 0</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object1" model="openacademy.openacademy"> -->
<!-- <field name="name">Object 1</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object2" model="openacademy.openacademy"> -->
<!-- <field name="name">Object 2</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object3" model="openacademy.openacademy"> -->
<!-- <field name="name">Object 3</field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="object4" model="openacademy.openacademy"> -->
<!-- <field name="name">Object 4</field> -->
<!-- </record> -->
<!-- -->
</data>
</odoo>
~~~
`openacademy/models.py`
~~~
# -*- coding: utf-8 -*-
from odoo import models, fields, api
# class openacademy(models.Model):
# _name = 'openacademy.openacademy'
# name = fields.Char()
~~~
`openacademy/security/ir.model.access.csv`
~~~
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_openacademy_openacademy,openacademy.openacademy,model_openacademy_openacademy,,1,0,0,0
~~~
`openacademy/templates.xml`
~~~
<odoo>
<data>
<!-- <template id="listing"> -->
<!-- <ul> -->
<!-- <li t-foreach="objects" t-as="object"> -->
<!-- <a t-attf-href="{{ root }}/objects/{{ object.id }}"> -->
<!-- <t t-esc="object.display_name"/> -->
<!-- </a> -->
<!-- </li> -->
<!-- </ul> -->
<!-- </template> -->
<!-- <template id="object"> -->
<!-- <h1><t t-esc="object.display_name"/></h1> -->
<!-- <dl> -->
<!-- <t t-foreach="object._fields" t-as="field"> -->
<!-- <dt><t t-esc="field"/></dt> -->
<!-- <dd><t t-esc="object[field]"/></dd> -->
<!-- </t> -->
<!-- </dl> -->
<!-- </template> -->
</data>
</odoo>
~~~
#### 對象關系映射
Odoo的關鍵組件是ORM層。這個層避免了大量手寫SQL,并提供擴展性和安全性。業務對象被聲明為`Model`類的擴展類,并自動將它們集成到持久層中。可以通過定義時設置屬性來配置模型。最重要的屬性是`_name`,必填屬性,它定義了模塊在Odoo系統中的名稱。一個最簡單的模型定義:
~~~
from odoo import models
class MinimalModel(models.Model):
_name = 'test.model'
~~~
#### 模型字段
字段定義了模型中需要存儲的內容和存儲的位置。字段通過類的屬性來定義:
~~~
from odoo import models, fields
class LessMinimalModel(models.Model):
_name = 'test.model2'
name = fields.Char()
~~~
**通用屬性**
和模型一樣,字段也可以配置,字段通過屬性參數的方式來配置:
~~~
name = field.Char(required=True)
~~~
一些屬性可以用于所有字段,以下是最常見的屬性:
`string(unicode,default: field's name)`
用戶界面中的字段標簽(用戶可見)
`required(bool,default:False)`
如果為True,這個字段不能為空,它必須有一個默認值或者在創建記錄時總是給定一個值。
`help (unicode, default: '')`
長格式,在用戶界面上顯示的提示。
`index (bool, default: False)`
請求Odoo在列上創建數據庫索引。
**簡單字段**
有兩大類字段:簡單字段和關聯字段,簡單字段的值是存儲在模型表中的原子值,而關聯字段是指向模型(相同模型或不同模型)的記錄行。
簡單字段的例子如:Boolean、Date、Char
關聯字段的例子如:Many2One、One2Many、Many2Many
**保留字段**
Odoo在所有模型中都創建幾個固定字段,這些字段由系統管理,用戶程序不應寫入。但是可以在用戶程序中讀取:
`id(Id)`
模型中記錄的唯一標識符
`create_date(Datetime)`
記錄的創建日期
`create_uid(Many2one)`
創建記錄的用戶
`write_date(Datetime)`
記錄的最后修改時間
`write_uid(Many2one)`
上次修改記錄的用戶
**特殊字段**
默認情況下,Odoo的name在所有模型上還需要一個字段,用于顯示和搜索。用于這些目的的字段可以通過設置字段`_rec_name`來實現。
> 練習定義模型,在openacademy模塊中定義新的數據模型*課程*,每門課程包含兩個字段,標題和描述,其中標題是必填字段。編輯文件`openacademy/models/models.py`以包含`Course`類。
`openacademy/models.py`
~~~
from odoo import models, fields, api
class Course(models.Model):
_name = 'openacademy.course'
name = fields.Char(string="Title", required=True)
description = fields.Text()
~~~
#### 數據文件
Odoo是一個高度數據驅動的系統,雖然行為是通過Python代碼制定的,但一些模塊的值是在加載時通過數據文件設置的。
> 提示:
> 一些模塊的作用僅僅是為了將數據添加到Odoo中
模塊數據通過帶有`<record>`元素的XML數據文件來聲明。每個`<record>`元素創建或更新數據庫中的一個記錄行。
~~~
<odoo>
<data>
<record model="{model name}" id="{record identifier}">
<field name="{a field name}">{a value}</field>
</record>
</data>
</odoo>
~~~
* `model`是在記錄行中記錄的Odoo模型名稱
* `id`是外部標識符,它允許引用記錄(而不必知道其在數據庫中的標識符)
* `<field>`,每個`<field>`對應數據行中的一個字段,name屬性是字段名(例如*description*),而`body`就是字段的值。
數據文件通過在manifest文件聲明而被載入,他們既可以在`data`列表聲明(始終載入)也可以在`demo`列表聲明(僅在演示模式下載入)
> 練習定義演示數據,添加演示數據以填充*Course*模型的數據,編輯文件`openacademy/demo/demo.xml`來添加演示數據
`openacademy/demo/demo.xml`
~~~
<odoo>
<data>
<record model="openacademy.course" id="course0">
<field name="name">Course 0</field>
<field name="description">Course 0's description
Can have multiple lines
</field>
</record>
<record model="openacademy.course" id="course1">
<field name="name">Course 1</field>
<!-- no description for this one -->
</record>
<record model="openacademy.course" id="course2">
<field name="name">Course 2</field>
<field name="description">Course 2's description</field>
</record>
</data>
</odoo>
~~~
#### 操作和菜單
操作和菜單是數據庫中的常規數據,通常以數據文件聲明。操作可以通過三種方式觸發:
1.點擊菜單項(鏈接到特定操作)
2.點擊視圖中的按鈕(如果這些按鈕已經被連接到操作)
3.作為對象的上下文操作
因為菜單的聲明相對復雜,所以有個一個`<menuitem>`的快捷方式來聲明`ir.ui.menu`菜單對象,并將其更容易的連接到對應的操作。
~~~
<record model="ir.actions.act_window" id="action_list_ideas">
<field name="name">Ideas</field>
<field name="res_model">idea.idea</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_ideas" parent="menu_root" name="Ideas" sequence="10"
action="action_list_ideas"/>
~~~
> 危險
> 操作必須在XML文件中對應的菜單之前聲明.數據文件是按順序執行的,操作的`id`必須在對應的菜單建立之前就存在于數據庫中。
>
> 練習定義新菜單項,在開放學院菜單項下定義新菜單項來訪問課程。用戶應該能夠:
>
> * 顯示所有課程的列表
> * 建立或編輯課程
> 1.建立`openacademy/views/openacademy.xml`以創建操作和能夠觸發操作的菜單項。
> 2.添加這個文件到`openacademy/__manifest__.py`下的`data`列表。
`openacademy/__manifest__.py`
~~~
'data': [
# 'security/ir.model.access.csv',
'templates.xml',
'views/openacademy.xml',
],
# only loaded in demonstration mode
'demo': [
~~~
`openacademy/views/openacademy.xml`
~~~
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<!-- window action -->
<!--
The following tag is an action definition for a "window action",
that is an action opening a view or a set of views
-->
<record model="ir.actions.act_window" id="course_list_action">
<field name="name">Courses</field>
<field name="res_model">openacademy.course</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">Create the first course
</p>
</field>
</record>
<!-- top level menu: no parent -->
<menuitem id="main_openacademy_menu" name="Open Academy"/>
<!-- A first level in the left side menu is needed
before using action= attribute -->
<menuitem id="openacademy_menu" name="Open Academy"
parent="main_openacademy_menu"/>
<!-- the following menuitem should appear *after*
its parent openacademy_menu and *after* its
action course_list_action -->
<menuitem id="courses_menu" name="Courses" parent="openacademy_menu"
action="course_list_action"/>
<!-- Full id location:
action="openacademy.course_list_action"
It is not required when it is the same module -->
</data>
</odoo>
~~~
作者:luohuayong
鏈接:http://www.jianshu.com/p/06e38310a465
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
- 開發教程
- Odoo10開發教程一(構建模塊)
- Odoo10開發教程二(基本視圖)
- Odoo10開發教程三(模型關聯)
- Odoo10開發教程四(繼承)
- Odoo10開發教程五(計算字段和默認值)
- Odoo10開發教程六(高級視圖)
- Odoo10開發教程七(工作流和安全)
- 參考手冊
- odoo V10中文參考手冊(一:ORM API)
- odoo V10中文參考手冊(指導規范)
- 技巧
- odoo 常用widget
- Odoo(OpenERP)開發實踐:菜單隱藏(1)
- Odoo(OpenERP)開發實踐:菜單隱藏(2)
- Odoo(OpenERP)開發實踐:數據模型學習
- Odoo中自動備份數據庫
- Odoo(OpenERP)應用實踐: 使用db-filter參數實現通過域名指定訪問哪個數據庫
- Odoo(OpenERP)配置文件openerp-server.conf詳解
- Odoo(OpenERP v8)數據模型(Data Model)
- odoo10學習筆記十七:controller
- Qweb定義