zoukankan      html  css  js  c++  java
  • [精]Odoo 8.0深入浅出开发教程-模块开发基础

    參考资料点击这里.

    构建Odoo模块

    模块组成

    • 业务对象

      业务对象声明为Python类, 由Odoo自己主动加载.

    • 数据文件

      XML或CSV文件格式, 在当中声明了元数据(视图或工作流)、配置数据(模块參数)、演示数据等.

    • Web控制器

      处理Web浏览器发来的requests.

    • 静态web数据

      Web用到的图像, CSS或JavaScript文件.

    模块结构

    一个Odoo模块也是一个Python模块, 存放在一个文件夹中, 包括一个__init__.py文件, 用于导入其它Python模块.

    from . import mymodule
    

    odoo.py提供了一个子命令scaffold能够方便地创建一个空的模块.

    $ odoo.py scaffold <module name> <where to put it>
    

    命令运行后, 将会创建一个子文件夹而且当中包括了Odoo模块所需的一些基本文件.

    练习 #1

    运行 ./odoo.py scaffold openacademy addons, 在addons文件夹下创建一个名为openacademy的模块, 生成的文件夹文件结构例如以下.

    openacademy
    ├── __init__.py
    ├── __openerp__.py
    ├── controllers.py
    ├── demo.xml
    ├── models.py
    ├── security
    │   └── ir.model.access.csv
    └── templates.xml
    

    各文件内容请查看文件或查看原文, 然后对__openerp__.py中的几种标识文本进行改动.

    对象关系映射

    ORM层是Odoo的一个关键组件, 它能够避免大部分的SQL语句编写从而提高扩展性和安全性.

    业务对象用派生自Model的Python类(模型)来编写, 该类的_name属性定义了模型在Odoo系统中的名称.

    from openerp import models
    class MinimalModel(models.Model):
        _name = 'test.model'
    

    字段

    字段定义模型能够存储什么以及在哪里存储, 字段在模型类中用属性来定义.

    from openerp import models, fields
    
    class LessMinimalModel(models.Model):
        _name = 'test.model2'
    
        name = fields.Char()
    

    通用属性

    与模型相似, 字段也能够通过參数传递对其进行设定:

    name = field.Char(required=True)
    

    字段的经常使用属性有:

    • string (unicode, default: field’s name)

      The label of the field in UI (visible by users).

    • required (bool, default: False)

      If True, the field can not be empty, it must either have a default value or always be given a value when creating a record.

    • help (unicode, default: ‘’)

      Long-form, provides a help tooltip to users in the UI.

    • index (bool, default: False)

      Requests that Odoo create a database index on the column

    简单字段

    字段能够分为两类: 简单字段和关系字段. 前者为原子值, 直接保存在模型相应的数据库表中; 后者连接到其它的记录上(能够是同样的模型也能够是不同的模型).

    Boolean, Date, Char这些都是简单字段.

    保留字段

    Odoo在模型中自己主动创建并维护一些字段, 这些字段就是保留字段, 这些字段数据不须要也不应该手动去改动.

    • id (Id)

      the unique identifier for a record in its model

    • create_date (Datetime)

      creation date of the record

    • create_uid (Many2one)

      user who created the record

    • write_date (Datetime)

      last modification date of the record

    • write_uid (Many2one)

      user who last modified the record

    特殊字段

    默认情况下, Odoo要求模型中有一个name字段, 用于显示和搜索, 通过设置_rec_name也能够达到这种目的.

    练习 #2

    在openacademy模块中定义一个新的模型Course, openacademy/models.py内容例如以下:

    # -*- coding: utf-8 -*-
    from openerp import models, fields, api
    class Course(models.Model):
        _name = 'openacademy.course'
    
        name = fields.Char(string="Title", required=True)
        description = fields.Text()
    

    数据文件

    Odoo是一个高度数据驱动的系统, 尽管使用Python代码来定制模块行为, 但非常多模块数据是在其加载时setup的, 而且有些模块仅仅为Odoo加入数据.

    通过数据文件来定义模块数据, 比如能够使用XML文件里的<record>元素定义数据, 每个<record>元素创建或者更新数据库中的一条记录, 形式例如以下:

    <openerp>
        <data>
            <record model="{model name}" id="{record identifier}">
                <field name="{a field name}">{a value}</field>
            </record>
        </data>
    <openerp>
    
    • model

      Odoo模型名.

    • id

      外部ID(External Identifier), 通过它能够引用到记录(而且不须要知道记录所在的数据库ID).

    • 元素

      name属性用于确定字段名称(比如description), 该元素的body给出字段的值.

    数据文件必须在模块加载清单文件列表中, 也就是__openerp__.py的’data’列表(所有加载)或’demo’列表(仅仅有设定为加载演示数据才会加载)中.

    练习 #3

    创建一个数据文件来向Course中加入数据, 编辑openacademy/demo.xml, 并确认__openerp__.py的’demo’列表中有该文件.

    <openerp>
        <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>
    </openerp>
    

    动作和菜单

    在Odoo中, 动作和菜单都是定义在数据库中的数据记录, 一般通过数据文件来定义.

    动作能够由三种方式触发:

    • 点击菜单项(菜单项链接到特定动作)
    • 点击视图上的按钮(假设按钮连接到动作)
    • 作为对象的上下文动作

    使用<menuitem>声明一个ir.ui.menu并将其连接到一个action, 能够用以下的形式的代码.

    <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"/>
    

    注意: action必须先于menu的连接使用定义, 数据文件在加载时顺序地运行, 所以动作的ID必须首先存在于数据库中才干使用.

    练习 #4

    定义一个新的菜单项訪问OpenAcademy课程.

    创建openacademy/views/openacademy.xml文件, 并在当中加入动作和菜单.

    <?

    xml version="1.0" encoding="UTF-8"?

    > <openerp> <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> </openerp>

    在__openerp__.py中加入这个数据文件名称到’data’.

    'data': [
            # 'security/ir.model.access.csv',
            'templates.xml',
            'views/openacademy.xml',
        ],
    

    更新模块后能够看到菜单, 操作看看效果.

    基本视图

    视图定义了模型数据怎样显示, 每种类型的视图代表一种数据可视化模式.

    主要的视图定义

    一个视图是以一条ir.ui.view模型数据的形式定义的.

    <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>
    

    Tree views

    Tree view也被称为list views, 在一个表格中显示记录. 根元素是<tree>, 最简形式的tree view仅仅是简单地列出每条记录的多个字段, 每个字段为一列.

    <tree string="Idea list">
        <field name="name"/>
        <field name="inventor_id"/>
    </tree>
    

    Form views

    Form用于创建或编辑单条记录, 根元素是<form>, 能够在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>
    

    练习 #5

    为openacademy创建form view, views/openacademy.xml数据文件里添加<record model=”ir.ui.view”…>内容.

    <?xml version="1.0" encoding="UTF-8"?>
    <openerp>
        <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",
    

    更新模块, 创建一个Course, 能够看到form view变了.

    练习 #6

    使用notebook. 在form view中, 将description字段放在一个tab中, 方便随后加入其它tabs, 对练习#5的form view数据做例如以下改动.

            <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>
    

    更新模块, 看效果.

    More

    还能够使用HTML为form view提供更加灵活的布局, 比如以下的样例.

    <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 views

    Search views用来自己定义list views及其它统计/多条记录视图中的搜索字段. 根元素为<search>, 其子元素定义了在哪些字段上进行搜索.

    <search>
        <field name="name"/>
        <field name="inventor_id"/>
    </search>
    

    假设一个模型未定义相应的Search view, odoo自己主动创建一个仅搜索name字段的search view.

    练习 #7

    加入title以及description搜索, 在views/openacademy.xml中定义search view.

        </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",
    

    更新模块, 搜索框输入字符后能够看到下方能够选择搜索description字段.

    模型中的关联

    概述

    一个模型中的记录可能关联到其它模型的记录, 比如销售订单记录会关联到一个包括客户信息的客户记录.

    练习 #8

    为了说明数据关联, 首先添加新的模型.

    Open Academy模块中, 一个session是一个在特定时间针对特定听众讲授课程的过程. 须要为session创建相应的模型.

    session具有name, 開始日期, 持续时间以及座位数量等. 此外还须要加入相应的action和menuitem显示模型数据.

    首先在openacademy/models.py中创建Session类.

    class Session(models.Model):
        _name = 'openacademy.session'
    
        name = fields.Char(required=True)
        start_date = fields.Date()
        duration = fields.Float(digits=(6, 2), help="Duration in days")
        seats = fields.Integer(string="Number of seats")
    

    然后在openacademy/view/openacademy.xml中加入用于訪问session模型的action和menuitem定义.

            <!-- Full id location:
                 action="openacademy.course_list_action"
                 It is not required when it is the same module -->
    
            <!-- session form view -->
            <record model="ir.ui.view" id="session_form_view">
                <field name="name">session.form</field>
                <field name="model">openacademy.session</field>
                <field name="arch" type="xml">
                    <form string="Session Form">
                        <sheet>
                            <group>
                                <field name="name"/>
                                <field name="start_date"/>
                                <field name="duration"/>
                                <field name="seats"/>
                            </group>
                        </sheet>
                    </form>
                </field>
            </record>
    
            <record model="ir.actions.act_window" id="session_list_action">
                <field name="name">Sessions</field>
                <field name="res_model">openacademy.session</field>
                <field name="view_type">form</field>
                <field name="view_mode">tree,form</field>
            </record>
    
            <menuitem id="session_menu" name="Sessions"
                      parent="openacademy_menu"
                      action="session_list_action"/>
        </data>
    </openerp>
    

    digits=(6,2)确定浮点数的精度, 6表示总的数字位数(不包括小数点), 2表示小数点后的位数. 所以, digits=(6,2)小数点前最多4位.

  • 相关阅读:
    [NOIP2017]宝藏 子集DP
    [NOI2017]蔬菜 贪心
    hihoCoder#1698 : 假期计划 组合数
    KNIGHTS
    动态图连通性(线段树分治+按秩合并并查集)
    CF868F Yet Another Minimization Problem 分治决策单调性优化DP
    【POJ】【3308】Paratroopers
    【BZOJ】【3437】小P的牧场
    【BZOJ】【3156】防御准备
    【BZOJ】【1010】【HNOI2008】玩具装箱Toy
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/7338602.html
Copyright © 2011-2022 走看看