开启/关闭Odoo服务器
Odoo使用客户端/服务器体系结构,客户端是通过RPC访问Odoo 服务器的Web浏览器。
业务逻辑和扩展通常在服务器端执行,尽管支持客户端特征(例如像交互式地图的新数据表示)可以添加到客户端。
为了启动服务器,只需调用shell中的命令Odoo-bin,必要时将完整路径添加到文件中:
odoo-bin
服务器通过从终端点击Ctrl-C两次或杀死相应的OS进程而停止。
建立一个Odoo模块
服务器和客户端扩展都被打包为可选地加载在数据库中的模块。
Odoo模块可以向Odoo系统添加全新的业务逻辑,或者更改和扩展现有业务逻辑:可以创建一个模块来将国家的会计规则添加到Odoo的通用会计支持中,而下一个模块则为公共汽车车队的实时可视化提供支持。
因此,Odoo中的一切都以模块开始和结束。
模块的布局
Odoo模块可以包含多个元素:
业务对象
声明为Python类,这些资源将根据Odoo的配置自动持久
数据文件
XML或CSV文件声明元数据(视图或工作流)、配置数据(模块参数化)、演示数据等
网络控制器
处理来自Web浏览器的请求
静态Web数据
Web界面或网站使用的图像、CSS或JavaScript文件
模块结构
每个模块是模块目录内的目录。模块目录通过--addons-path
选项指定。
提示
大多数命令行选项也可以使用配置文件来设置
通过它的清单声明一个Odoo模块。 请参阅有关它的清单文档。
一个模块也是一个带有__init__.py文件的Python包,包含模块中各种Python文件的导入指令。
例如,如果模块有一个单独的mymodule.py文件,__init__.py可能包含:
from . import mymodule
Odoo提供了一种帮助建立一个新模块的机制,odoo-bin有一个子命令scaffold来创建一个空模块:
$ odoo-bin scaffold <module name> <where to put it>
该命令为您的模块创建子目录,并自动为模块创建一系列标准文件。它们中的大多数只包含注释代码或XML。大多数这些文件的用法将在本教程中说明。(译者注:在进入从github上下载的odoo根目录后,执行上面的命令,需要在odoo-bin前面使用python命令)
练习
模块创建
使用上面的命令行创建一个空模块Open Academy,并将其安装在Odoo。
- 调用命令
odoo-bin scaffold openacademy myaddons
。[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并提供可扩展性和安全性服务[2]。
业务对象被声明为扩展了Model
的Python类,这些类将它们集成到自动持久化系统中。
模型可以通过在其定义中设置多个属性来配置。最重要的属性是_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
, 默认的: 字段的name)
UI中字段的标签(用户可见)
required
(bool
, 默认的: False
)
如果True,字段不能为空,则它必须具有默认值,或者在创建记录时总是被赋予一个值
help
(unicode
, 默认的: ''
)
长的表单,为UI中的用户提供帮助工具提示
index
(bool
, 默认的: False
)
请求Odoo在列上创建数据库索引
简单字段
字段有两大类:“简单”字段,这些字段是直接存储在模型表中的原子值和链接记录(同一模型或不同模型)的“关系”字段。
保留字段
Odoo在所有模型[1]中创建了几个字段。这些字段由系统管理,不应写入。如果有用或必要,它们可以被读取:
id
(Id
)
模型中记录的唯一标识
create_date
(Datetime
)
记录的创建日期
create_uid
(Many2one
)
创建记录的用户
write_date
(Datetime
)
记录的最后修改日期
write_uid
(Many2one
)
上次修改记录的用户
特殊字段
默认情况下,Odoo还需要所有模型上的name
字段,这是为了所有显示和搜索行为。用于这些目的的字段可以通过设置_rec_name
来重写。
练习
定义一个模型
在openacademy 模块中定义一个新的数据模型Course。课程有标题和描述。课程必须有标题。
编辑文件 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>
元素具有一个name
,其是模型中的字段的名称(例如description
)。它们的内容是字段的值
数据文件必须在要加载的清单文件中声明,它们可以在'data'列表(总是加载)或'demo'列表中声明(仅加载在演示模式中)。
练习
定义演示数据
创建示范性数据填充带有一些示范课程的Courses 模型。
编辑文件 openacademy/demo/demo.xml
以包含某些数据。
openacademy/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>
动作和菜单
动作和菜单是数据库中的常规记录,通常通过数据文件声明。动作可以通过三种方式触发:
- 通过点击菜单项 (链接到特定的动作)
- 通过单击视图中的按钮 (如果这些连接到动作)
- 作为对象的上下文动作
因为菜单有一些复杂的声明,所以有一个<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必须存在于数据库中。
练习
定义新的菜单条目
定义新菜单项以访问OpenAcademy 菜单项下的课程。用户应该能够:
- 显示所有课程的列表
- 创建/修改课程
- 创建带有动作和触发动作的菜单的openacademy/views/openacademy.xml
- 将其添加到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>
基本视图
视图定义模型的记录显示方式。每种类型的视图代表可视化的模式(记录列表,它们的聚合图,…)。一般情况下,视图可以通过它们的类型(例如合作伙伴的列表)或具体地通过它们的id来请求。对于通用请求,将使用具有正确类型和最低优先级的视图(因此,每种类型的最低优先级视图是该类型的默认视图)。
视图继承允许更改在别处声明的视图(添加或删除内容)。
通用的视图声明
视图被声明为模型ir.ui.view的记录。视图类型由arch
字段的根元素暗示:
<record model="ir.ui.view" id="view_id">
<field name="name">view.name</field>
<field name="model">object_name</field>
<field name="priority" eval="16"/>
<field name="arch" type="xml">
<!-- view content: <form>, <tree>, <graph>, ... -->
</field>
</record>
危险
视图的内容是XML。
因此,必须将arch
字段声明为正确解析的type="xml"
树视图
树视图,也称为列表视图,以表格形式显示记录。
它们的根元素是<tree>
。树视图的最简单形式只列出表中显示的所有字段(每个字段作为列):
<tree string="Idea list">
<field name="name"/>
<field name="inventor_id"/>
</tree>
表单视图
表单用于创建和编辑单个记录。
它们的根元素是<form>
。它们由高级结构元素(groups、notebooks)和交互元素(buttons 和fields)组成:
<form string="Idea form">
<group colspan="4">
<group colspan="2" col="2">
<separator string="General stuff" colspan="2"/>
<field name="name"/>
<field name="inventor_id"/>
</group>
<group colspan="2" col="2">
<separator string="Dates" colspan="2"/>
<field name="active"/>
<field name="invent_date" readonly="1"/>
</group>
<notebook colspan="4">
<page string="Description">
<field name="description" nolabel="1"/>
</page>
</notebook>
<field name="state"/>
</group>
</form>
练习
使用XML定制表单视图。
为Course对象创建自己的表单视图。显示的数据应该是:课程name和description。
openacademy/views/openacademy.xml
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="arch" type="xml">
<form string="Course Form">
<sheet>
<group>
<field name="name"/>
<field name="description"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- window action -->
<!--
The following tag is an action definition for a "window action",
练习
Notebooks
在Course表单视图中,将描述字段放在选项卡下,这样以后更容易添加其他选项卡,包含附加信息。
修改Course表单视图如下:
openacademy/views/openacademy.xml
<sheet>
<group>
<field name="name"/>
</group>
<notebook>
<page string="Description">
<field name="description"/>
</page>
<page string="About">
This is an example of notebooks
</page>
</notebook>
</sheet>
</form>
</field>
表单视图还可以使用简单的HTML来进行更灵活的布局:
<form string="Idea Form">
<header>
<button string="Confirm" type="object" name="action_confirm"
states="draft" class="oe_highlight" />
<button string="Mark as done" type="object" name="action_done"
states="confirmed" class="oe_highlight"/>
<button string="Reset to draft" type="object" name="action_draft"
states="confirmed,done" />
<field name="state" widget="statusbar"/>
</header>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only" string="Idea Name" />
<h1><field name="name" /></h1>
</div>
<separator string="General" colspan="2" />
<group colspan="2" col="2">
<field name="description" placeholder="Idea description..." />
</group>
</sheet>
</form>
搜索视图
搜索视图自定义与列表视图(以及其他聚合视图)相关联的搜索字段。它们的根元素是<search>,它们由定义哪些字段可以被搜索的字段组成:
<search>
<field name="name"/>
<field name="inventor_id"/>
</search>
如果模型不存在搜索视图,Odoo生成一个只允许在name
字段上搜索的视图
练习
搜索课程
允许根据他们的标题或他们的描述搜索课程。
openacademy/views/openacademy.xml
</field>
</record>
<record model="ir.ui.view" id="course_search_view">
<field name="name">course.search</field>
<field name="model">openacademy.course</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<field name="description"/>
</search>
</field>
</record>
<!-- window action -->
<!--
The following tag is an action definition for a "window action",
[1] 它可能是disable the automatic creation of some fields
[2] 编写原始SQL查询是可能的,但需要小心,因为它绕过所有的Odoo认证和安全机制
[3] 关于此命令,首先要知道自己使用的python.exe是哪个?如下图
所以新建模块的命令为:E:\odoo-10.0>E:\odoo-10.0\venv\Scripts\python.exe odoo-bin scaffold openacademy
myaddons
下一篇:Odoo10教程---模块化二:模型间关系,继承,计算字段等
附上代码地址:https://download.csdn.net/download/mzl87/10386990
ps:有翻译不当之处,欢迎留言指正。
原文地址:https://www.odoo.com/documentation/10.0/howtos/backend.html