odoo

Packer.Odoo.10---Chapter 5

2017-10-09  本文已影响132人  F4A3

结构化应用数据

在前面的章节中,我们基本接触了建造Odoo后台应用的所有层面。下面我们就要具体分析‘model,views,business logic’这些组成Odoo应用的不同层面的细节。
首先我们来学习如何设计支持一个应用的数据的结构组成以及如何表达这些数据之间的联系。

组织应用的功能到模块中

首先,我们需要使用一个例子来帮我们理解这个概念。
Odoo的继承功能提供了有效的拓展机制。它允许我们不直接修改源代码来拓展已经存在的第三方应用。这个可组合性还确保了面向对象的开发模式,大的应用能够被分成各种小功能。这种避免复杂性的方法从技术角度跟用户体验角度看来都是非常有用的。所以我们通过添加额外的功能模块来改进我们的To-Do 应用。最后让它变成一个具有丰富功能的大应用。

介绍我们将要创建的 todo_ui 模块

在前面的章节中,我们首先创建了一个个人版的to-do task模块,然后通过继承把它扩展为多用户可以共享的应用。
现在,我们想要提升用户界面,增加一个看板板块,看板板块是一个简单的工作流工具,它把主题放在一个个列中,我们可以把这些主题从左边的列一步步传入右边的列,知道它们完成了整个工作流。现在,我们组织我们的任务放入以Waiting,Ready,Started,Done这样的阶段(Stages)为列名的视图中。
我们首先通过添加数据结构来保证这个视觉效果的底层实现。添加阶段(Stages),让这个阶段模型支持标签,以便我们能够根据主题来对tasks进行分类。我们在本章中只关注模型的数据结构。关于用户界面的讨论会放到下一章来讲解。
在设计支持模型时,首要的事就是理解数据的结构组成。
我们现在已经有了最中心的模型实体—— To-do Task
然后需要创建一个Stage模型跟一个tag模型。它们与我们的task模型之间有如下关系:

mkdir todo_ui
cd todo_ui
touch _init__.py
vim __manifest__.py

添加下面的内容

{
    'name': 'User interface improvements tp the To-Do app',
    'description': 'User friendly features.',
    'author': 'xer',
    'depends': ['todo_user'],
}

在Odoo中安装这个新模块


创建新模型

为了让我们的to-do tasks拥有看板板块,我们需要使用Stages。Stages 代表了板块中的列。每个task都会填充到这些列里面。

  1. 编辑__init__.py来导入models
    `from . import models
  2. 创建todo_ui/models文件夹,在其下添加init.py,让它变为一个python包文件.from . import todo_model`
  3. 然后创建todo_model.py来定义我们的新模型
from odoo import api,models,fields

class Tag(models.Model):
   _name = 'todo.task.tag'
   _description = 'To-do Tag'
   name = fields.Char('Name',40, translate=True)
class Stage(models.Model):
   _name = 'todo.task.stage'
   _description = 'To-do Stage'
   _order = 'sequence,name'
   name = fields.Char('Name',40, translate=True)
   sequence = fields.Integer('Sequence')

上面的代码我们定义2个与to-do tasks相关联的新模型。
注意到 task stages, 我们有个继承models.Model的python类==>Stage.这定义了一个新的名为todo.task.stage的Odoo模型.

模型属性

模型类中可以使用附加的属性来控制模型的行为,下面是那些最常使用的属性:

模型跟Python类.

Odoo模型被存放在中心注册处,在老版本的Odoo中,可以通过pool来获取到.pool是一个字典,通过模型的名称保存着与所有Odoo模型实例之间的联系.我们可以使用self.env['x']来获取到‘x’这个模型代表类。
模型的名称是十分重要的因为它们用作键来获取在中心注册处注册过的模型。模型的起名规范是使用一个以.为分隔符的小写字符串,例如todo.task.stage.
Python类的命名并无严格限制,符合PEP8,按照驼峰命名法即可.

临时跟抽象模型

在大多数情况中,我们编写的python模型类都是继承自Odoo的models.Model.Odoo另外提供了2个模型

检查已存在的模型

打开 Settings |Technical | Database Structure | Models。这里保存了所有的‘models’。

models list

创建字段

Oodd中的字段主要分为基础字段跟关系型字段

  1. 基础字段类型

我们在我们刚创立的‘Stage’模型中添加如下字段

class Stage(models.Model):
    _name = 'todo.task.stage'
    _description = 'To-do Stage'
    _order = 'sequence,name'

    name = fields.Char('Name')
    desc = fields.Text('Description')
    state = fields.Selection([('draft', 'New'), ('open', 'Started'), ('done', 'Closed')], 'State')
    docs = fields.Html('Documentation')
    sequence = fields.Integer('Sequence')
    perc_complete = fields.Float('% Complete', (3, 2))
    date_effective = fields.Date('Effective Date')
    date_changed = fields.Date('Last Changed')

    fold = fields.Boolean('Folded?')
    image = fields.Binary('Image')
字段常见属性:
states = {'done':[('readonly',True)]}
特殊名字的字段
  1. Odoo自动生成的字段名

  1. 关系型字段

以我们的模块为例,我们有如下的模型之间的关系:

class TodoTask(models.Model):
    _inherit = 'todo.task'
    stage_id = fields.Many2one('todo.task.stage', 'Stage')
    tag_ids = fields.Many2many('todo.task.tag', string='Tags')
Many-to-one 关系:

Many2one的主要属性:

Many-to-many关系:

创立了第三张表来表示两个多对多关系模型之间的具体映射,中间表的命名是自动的,规则是两张模型表名之后加入'_rel'.但是当表名太长超过psql规定的63个字符时,我们需要自己来定义表名.
我们有2中方法定义Many2many字段.通常使用字典参数,因为这样容易理解。举例:
Task跟Tag模型之间创立关系:
在Task模型中.

tag_ids = fields.Many2many(
        comodel_name='todo.task.tag',
        relation='todo_task_tag_rel',
        column1='task_id',
        column2='tag_id',
        string='Tags')

在Tag模型中.

task_ids = fields.Many2many('todo.task',string='Tasks')
One-to-many 关系。

Odoo中的One2many不能单独存在, 是于Many2one相对应的。实际上并没什么意义,但是对于反向遍历多对一关系时很有用处。
在Stage模型中,我们这样定义一对多的存在:

tasks = fields.One2many('todo.task', 'stage_id', 'Tasks in this stage')

One2many字段接收3个可选参数:

  1. 关联模型----'todo.task'
  2. 关联模型中的相关字段-----'stage_id' 表示与task中的'stage_id'字段互相对于
  3. 字符串标题名称

分层关系

父子树关系结构也可以看做是Many2one


关联字段使用动态关系

在task模型中
如下:

   refers_to = fields.Reference([('res.user', 'User'), ('res.partner', 'Partner')], 'Refers to')

我们可以直接通过Reference字段来让task跟‘User’,‘Partner’建立关联。Reference字段的定义与Selection比较相似。

计算字段

字段的值可以通过函数计算得到。计算字段的定义很简单,跟普通字段一样,只是在属性中添加一个compute属性.
举例:
Stages模型中有一个fold字段,这个字段是一个布尔值,用来标识是否折叠。在我们的TodoTask模型中对它的值进行计算获取。

    stage_fold = fields.Boolean('Stage Folded?', compute='_compute_stage_fold',)

    @api.depends('stage_id.fold')
    def _compute_stage_fold(self):
        for task in self:
            task.stage_fold = task.stage_id.fold

上面的代码在Task模型中添加了一个stage_fold字段,并且使用了_compute_stage_fold这个函数来对其计算取值.
@api.depends装饰器中需要放入我们计算取值需要的字段.可以认为是计算函数需要的参数.

搜索跟编辑计算字段

我们刚才创建的计算字段并不能被搜索或者写入数据,只是一个可读字段.为了增加这两个操作.我们使用

    stage_fold = fields.Boolean('Stage Folded?', compute='_compute_stage_fold',
                                search='_search_stage_fold',
                                inverse='_write_stage_fold'
                                )
    def _search_stage_fold(self, operator, value):
        return [('stage_id.fold', operator, value)]

    def _write_stage_fold(self):
        self.stage_id.fold = self.stage_fold

上面代码中,search代表的函数表示该字段可以被搜索。inverse代表的函数表示改变stage_fold的值可以反向写入到stage_id.fold字段中.

存储计算字段.

在计算字段定义时添加属性store = True即可.当计算字段所依赖的数据改变时,它也会相应的进行更新.

依赖字段

刚才我们定义的计算字段其实就是在Task模型中把Stage的fold字段给复制了出来.我们使用依赖字段也可以实现这一操作.
定义这样的字段跟普通字段一样,唯一不同就是添加一个related属性,related属性的值通过'.'操作符来直接获取我们需要的目标字段.

    stage_state = fields.Selection(related='stage_id.state', string='Stage State',store=True, inverse='_write_state')

就像上面的代码。我们直接在Task模型中定义了依赖字段。直接获取到了Stage中的state值。


模型限制。

为了防止非法数据,Odoo支持2种模型数据限制:

  1. SQL限制:SQL限制的原理是通过Psql数据库的数据库表定义来防止非法数据的产生。
    使用_sql_constraints这个类属性来进行定义。
    它是一个元组列表,格式为 限制名称,SQL限制条件,错误信息
SQL限制
  1. Python限制:
    我们使用@api.constraints装饰器来对需要限制的字段进行规范限制。
    举例,我们的Task名字至少是要5个字符:
    @api.constrains('name')
    def _check_name_size(self):
        for task in self:
            if len(task.name)< 5:
                raise ValidationError('Must have 5 chars!')

上面的代码表示当task的名字小于5个字符时,会抛出状态异常。Odoo会直接在视图界面发出警告。

上一篇 下一篇

猜你喜欢

热点阅读