整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

odoo模型层的记录集与操作

odoo模型层的记录集与操作

大多数框架一样,odoo模型层也是 Odoo技术框架最核心的部分了。了解了它的编写规则,可以说 Odoo的神秘面纱基本也会被掀开一半。

上面这是一段证书管理的 model 代码,下面来详细解释下 model 层各个字段

01

创建模型

创建类继承自 models.Model

_name : 创建 odoo模型内部标志符(数据表名称,名称以_连接存入数据库),必须是全局唯一的

_description: 描述,方便用户的模型记录解释

_inherit : 继承 (设置继承自另外那个表,可以进行字段方法的添加修改)

02

字段类型

可以定义字段的类型

1.Char :

单行文本

name=fields.Char(string=u'单据编号')

2.Text :

多行文本

note=fields.Text(u'备注')

3.Html:

存储为带格式的文本字段

html=fields.Html()

4.Datetime:

日期时间类型

date_order=fields.Datetime(string=u'订单日期')

5.Date

delivery_date=fields.Date(u'交货日期')

6.Selection:

下拉选择列表(前一个参数是存储在数据库的值,后一个参数是前端展示的描述)

type=fields.Selection([ (u'default', u'默认')], string=u'类型', default=u'default')

7.Boolean:

布尔类型

active=fields.Boolean(default=True, string=u'是否归档')

8.Integer:

整型

sequence=fields.Integer(string=u'排序', default=10)

9.Binary:

存储为二进制文件

files=fields.Binary(u'文件',filters='*.xlsx', required=True)

10.Float:

浮点型

amount=fields.Float(string=u'总计')

11.Monetary:

与浮点型类似,但带有货币的特殊处理

price_subtotal=fields.Monetary(compute='_compute_amount', string=u'小计', readonly=True)

12.Many2one:

多对一

order_id=fields.Many2one('sale.order', string=u'销售订单', ondelete='cascade', index=True, copy=False)

13.One2many:

一对多

One2many 是一个一对多的关联字段,与 Many2one 对应

order_line=fields.One2many('sale.order.line', 'order_id', string=u'销售明细',states=READONLY_STATES,copy=True)

14.Many2many:

多对多

一本书可以有多个作者,一个作者可以有多本书class Book(models.Model):

author_ids=fields.Many2many(‘res.partner’, string=‘Authors’)

class Partner(models.Model):

book_ids=fields.Many2many(‘library.book’, string=‘Authored Books’)

03

字段属性

# string 字段显示名label,任意字符串

# help='str' 用于悬挂帮助信息提示

# readonly=True 本字段是否只读,缺省值:False

# required=True 本字段是否必须的,缺省值:False。

# index=True 设置字段创建索引

# select=True 相关联字段下拉列表

# default 设置字段的默认值

name=fields.Char(default="Unknown")

user_id=fields.Many2one('res.users', default=lambda self:self.env.user)

# states 定义特定state才生效的属性,格式为:{'name_of_the_state': list_of_attributes},

其中list_of_attributes是形如[('name_of_attribute', value), ...]的tuples列表。

例子(参见account.transfer): 'partner_id': fields.many2one('res.partner', 'Partner',

states={'posted':[('readonly',True)]}),

# groups 设置权限组访问可见,值为列表形式,元素是组的xml ids(也就是外部标识符)

# copy=False 设置字段不能被复制,普通字段是True, 在 one2many是默认是False

# oldname='field' 当一个字段在新版本重命名了,指定老的字段,老的字段的数据会自动拷贝到新的字段中

# compute 给定一个方法名计算出该字段

# inverse 给定一个方法名反转该字段 (为了在计算字段设置值)

document=fields.Char(compute='_get_document', inverse='_set_document')

def _get_document(self):

for record in self:

with open(record.get_document_path) as f:

record.document=f.read()

def _set_document(self):

for record in self:

if not record.document: continue

with open(record.get_document_path()) as f:

f.write(record.document)

# search 给定一个方法名搜索该字段 (用在计算字段)

upper_name=field.Char(compute='_compute_upper', search='_search_upper')

def _search_upper(self, operator, value):

if operator=='like':

operator='ilike'

return [('name', operator, value)]

# store 设定该字段是否存在数据表中,在用了compute时为False ,其它默认是True

# compute_sudo 设定是否要超级用户来计算该字段,默认是False

# related 序列的字段名,用于关联字段,默认不存数据表中,可以store=True来存,

nickname=fields.Char(related='user_id.partner_id.name', store=True)

这里看出前面定义了user_id字段,这里是接着关联到 user_id这个字段把所要的信息提取出来

# company_dependent 定义该字段是不是公司依赖

# change_default 别的字段的缺省值是否可依赖于本字段,缺省值为:False。

例子(参见res.partner.address) 'zip': fields.char('Zip', change_default=True, size=24),

这个例子中,可以根据zip的值设定其它字段的缺省值,例如,可以通过程序代码,

如果zip为200000则city设为“上海”,如果zip为100000则city为“北京”。

# domain: 域条件,缺省值:[]。在many2many和many2one类型中,字段值是关联表的id,

域条件用于过滤关联表的record。例子: 'default_credit_account_id': fields.many2one('account.account',

'Default Credit Account', domain="[('type','!=','view')]"),

本例表示,本字段关联到对象('account.account')中的,type不是'view'的record。

# context 上下文

# invisible: 本字段是否可见,即是否在界面上显示本字段,缺省值True。

# selection: 只用于reference字段类型,参见前文reference的说明。

# size 只用于Char 设置可最大接收字符数

# translate=true 用于Text Char Html 本字段值(不是字段的显示名)是否可翻译,缺省值:False。

# ondelete 用于关联字段,定义删除方式

# manual

# deprecated=True 当用这个字段,日志会记录警告,主要是版本升级一些过渡字段

# password="True" 密码星号显示

# nolabel="1" 隐藏标签

# attr属性 可以定义多条件这段只读显示

# digits 格式化浮点数

<field digits="(14,3)" name="volume" attrs="{readonly:[('type','=','service')]}"

# default_focus 新开窗口光标位置

# Widget 多种部件显示格式 widget="one2many_list"

one2one_list, one2many_list, many2one_list, many2many,Url,Email,Image,float_time,reference

04

ORM装饰器

@api.multi

默认装饰器,如果我们需要自定义方法来对记录集执行一些操作。用这个,方法的逻辑通常包括对 self 的遍历

@api.one

用于操作单条记录(单例),弃用了。用@api.multi,在代码顶部添加一行 self.ensure_one(),来确保操作单条记录

@api.model

类静态方法,self作为模型的引用,无需包含实际记录。注意,不能从用户界面中的按钮使用这种类型的方法。

@api.onchange(‘字段值')

当用户编辑指定字段值时,立即执行一段业务逻辑。可用于执行验证,向用户显示消息或修改表单中的其他字段

@api.depends(field1,...)

用于计算字段函数,用于确保(重新)计算改变被触发

@api.constrains(field1,...)

用于验证函数,用于确保哪些约束生效被触发

以上~

随着企业信息化不断地深入和应用,无论大中小型企业,通过信息化甚至数智化,不断提高企业内部的运营效率,人财物达到最优配置,从而不断增加企业核心竞争力,有些行业领先的企业,要求管理层必须懂IT,一岗双责,否则就无法胜任现有管理岗位,全员信息化或数字化。特别对于制造企业来说,业务随着外部市场的变化也随时需要更新升级系统,以符合最新的企业管理模式,从系统开发角度来说,如何随需而变并进行快速响应用户的需求这个是一个现实又重要的课题通过Odoo可以很好地支持业务随时变化的需求,由于Odoo配置功能很强大,完成可以作为企业内部的低代码开发平台,笔者后续会针对Odoo写一系列的文章进行一些经验和实践的分享。

什么是Odoo?Odoo由OpenERP发展而来,Odoo现在有一套完整的业务应用,满足所有的业务需求,从网站/电子商务到制造,库存和会计,所有的领域无缝集成。这是第一次一个软件系统,被设计成能达到这么全面的功能覆盖。Odoo的底层结构很强大,所有模块都可以根据需要进行安装和御载,所以客户能像搭积木一样建构自己期望的系统。即使完全不安装与ERP相关的模块,仅利用 Odoo 自身的底层框架,也能构建出适合各种用途的系统,纯粹 B/S 架构。而这一切都是免费的,并且不受限于源代码,也不受限于用户数

Odoo总部位于欧洲比利时,拥有1700名员工,11个全球办事处和超过700万的全球用户。过去10年,每年的增长率超过50%。

Odoo的进化史,如下:

2005, TinyERP 1.0(2月), 2.0(5月),3.0(9月),基于 GPL协议GPL,是GNU General Public License的缩写,是GNU通用公共授权非正式的中文翻译,AGPL是GPL的一个补充, 在GPL的基础上加了一些限制。

2006, TinyERP 4.0(9月),仍然是GPL协议

----------------------第一次改名-------------------------------------------------

2009 OpenERP 5.0(4月),第一次重大改进,历时三年时间。

2011 OpenERP 6.0(1月), 基本web 的客户端,协议从GPL变为AGPL。

2012 OpenERP 6.2(2月), GTK客户端停止开发,引入Ajax。

2012 OpenERP 7.0(12 ), 增强了可用性。

------------------------第二次改名---------------------------------------------------

2014 Odoo 8.0(10月) 重写了仓库和WMS,引入了电商、POS、BI。

2015 Odoo 9.0(10月) 开启社区版和企业版双版本战略,社区版免费,企业版按用户收费 费,LGPL协议。

2016 Odoo 10.0(10月) 重写了 MRP模块,引入 MPS\PLM 概念,企业版按用户和模块收费。

2017 Odoo 11.0(10月) 重写了 Report,重写了Studio,支持Python 3,提升了速度和性能。

2018 Odoo 12.0(10月) 引入 物联网盒子,机器学习,报表设计器。

2019 Odoo 13.0(10月) 更强大的会计模块,更令人惊叹的网站设计,更实用的在线学习,更灵活地制造模块管理。

2020 Odoo 14.0(10月) 从功能上来说,也确实在ERP核心功能之外的网站、电商、HR等方面有不少功能增添,同时引入了全新前端框架OWL。

2021 Odoo 15.0(10月) OWL表单2.0发布,电子表格实时提供ERP数据。公式助手、编辑栏、查找和替换等(企业版功能)。

Odoo 15是一系列开源商业应用程序套装,此套装可满足中小型企业的一切应用需求,例如,企业基本的进销存、采购、销售、MRP生产制造、品保质量保障、企业招聘、员工合同、休假、午餐管理、内部论坛、车队管理、内部聊天IM沟通、客诉追溯管理、CRM客户关系管理、VOIP、E-Shop电子商务、网店、企业官方网站,财务会计、银行对账、资产管理、HR工资管理、预算管理、WMS仓库库存管理、POS街边小摊、社区商店、项目管理、条码、PLM等等。

从Odoo 11开始,定位不仅仅是开源ERP,已覆盖到企业的CRM、PLM、WMS、HR等全领域,一个应用满足所有中小企业需求,ODOO的应用界面,如下图:


Odoo是基于开源技术进行构建的,数据库采用开源老牌的数据库Postgresql,开发语言基于目前主流的Python等一系列开源技术和产品,并构建成熟稳定的架构,提供了强大的配置,定制和在线开发工具,确保通用化产品和灵活定制之间的平衡。

PostgreSQL 的历史简介:

PostgreSQL是一个功能强大的开源对象关系数据库系统,它使用并扩展了SQL语言,并结合了许多安全存储和扩展最复杂数据工作负载的功能。PostgreSQL的起源可以追溯到1986年,作为加州大学伯克利分校POSTGRES项目的一部分,并在核心平台上进行了30多年的积极开发。

PostgreSQL凭借其经过验证的架构,可靠性,数据完整性,强大的功能集,可扩展性以及软件背后的开源社区的奉献精神赢得了良好的声誉,以始终如一地提供高性能和创新的解决方案。PostgreSQL在所有主要操作系统上运行,自2001年以来一直是符合ACID标准的,并且具有强大的附加功能,例如流行的PostGIS地理空间数据库扩展器。毫无疑问,PostgreSQL已经成为许多人和组织的首选开源关系数据库。

开始使用PostgreSQL从未如此简单 - 选择您想要构建的项目,并让PostgreSQL安全可靠地存储您的数据。

Python:

1、 Python是一种计算机程序设计语言。是一种动态的、面向对象的脚本语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发。

2、Python就为我们提供了非常完善的基础代码库,覆盖了网络、文件、GUI、数据库、文本等大量内容,被形象地称作“内置电池(batteries included)”。用 Python开发,许多功能不必从零编写,直接使用现成的即可。

3、除了内置的库外,Python还有大量的第三方库,也就是别人开发的,供你直接使用的东西。当然,如果你开发的代码通过很好的封装,也可以作为第三方库给别人使用。

4、许多大型网站就是用Python开发的,例如YouTube、Instagram,还有国内的豆瓣。很多大公司,包括Google、Yahoo等,甚至NASA(美国航空航天局)都大量地使用Python。

同时Odoo不仅具有10多年的发展历史,Odoo官方每年都会发布更新一个大的全新版本,每次都会有很多新特性或新功能,而且具有强大的生态圈目前Odoo官网的应用商店已超过3万+扩展模块插件,其中一半插件是完全免费的,同时Odoo社区OCA也提供了很多免费好用的插件,对于我来说通过Odoo自带的项目模块,并通过下载一些项目相关的免费插件,像搭积木一样构建了一个功能完整的项目管理系统,同时项目管理相关的一些报表是通过开发实现的,其他基本都是通过配置实现。



Odoo价格优势

在带宽和服务器硬件允许的情况下,社区版没有使用用户数的限制,客户端不用额外安装软件只要用新版的chrome浏览器或者firefox浏览器即可。

对于生产和大多数企业来说,二次开发本来就不可避免,由于有大量预开发模块,Odoo在二次开发的速度和价格上有非常大的优势。

即使金蝶,用友,Sap,甲骨文的ERP是免费的,一旦你需要二次开发,动辄几十万几百万甚至上千万的价格还是让很多企业承受不起。

相对很多软件使用微软的sql,微软的Server系统和操作系统,微软的office,这些软件如果买正版,也是一笔不小的开销。

很多企业虽然买了正版的用友,金蝶,但微软的服务器系统,微软的数据库都是盗版,这为以后埋下不少隐患。

而Odoo用的服务器系统是Ubuntu Server他目前是自由免费的,PostgreSQL也是免费的。

如果自己找团队去开发Odoo这样一套系统,估计至少20个人开发5年,也就是差不多至少300万的开销。

投资成本分析





传统ERP项目

Odoo企业版

Odoo社区版

咨询培训

数万

软件许可

10-100万

每月12-72美元

免费

软件升级

3-30万

无 或 低

年服务费

合同15-30%

无 或 低

实现

合同65% - 75%

合同65% - 75%

Odoo产品优势

Odoo的前端用了较多的Javascript代码,这样保证了用户体验较好:输入关键字即出现的产品及联系人选项,大大提高了操作速度,(有不少软件都需要多操作一步搜索)。

非常强大的过滤及高级搜索功能 可以根据电话号码地址等字段搜索,可以根据客户或者产品来索引出此客户或者产品的销售情况,服务情况 。

方便查看各类单据了解产品的成本,售价的变化。比如可以显示现有库存量,查看产品的所有采购情况。

快速上线:不像其他软件,必须弄很多初始数据,有些初始数据比如产品名,会计期初帐OpenERP可以在后期慢慢弄,

更直观的数据:具有柱状,饼状,雷达,曲线等 直观的数据透视图表显示,有些模块还具有甘特图。



Odoo技术优势

B/S(浏览器-服务器)架构(方便了更新和二次开发),跨操作系统方面很有优势,平板,手机默认都可以用。采用Module为开发单元,采用MVC的架构,支持继承。B/S架构,支持各种操作系统和浏览器。

先进的数据库PostgreSQL,先进的语言Python,大量的预开发代码可以实现快速进行二次开发。

可以部署在云端(企业可以自己建云,建立一个更大的数据库)云计算特性很容易能把上下游整个供应链的资源都整合到Odoo中来。(通过更改Odoo设置还可以开放客户接口和供应商接口)

内置了社交系统:消息系统。并在各个模块都拥有非常灵活的搜索和高级搜索界面。



Odoo开源优势

几十人的团队开发十多年(目前官方团队有1700多人,至少还大约有6000名志愿者参与,用户数量超过700万)。

模块齐全,涵盖了个人助理,企业内部交流,客户关系管理CRM,进销存管理,生产管理,人力资源管理等等(以8.0来说目前已有4000多个功能模块已经适合绝大多数企业),并且Odoo不断的有新功能和新模块来适应更多的企业去运用。

它还是个很好的二次开发的平台,如果你不需要其自带的模块,你完全可以按照官方模块的写法,写自己的模块。

流程设计合理,除了初始化的数据(产品,客户,供应商)及少数单据(报价单,销售订单),大部分单据(出入库单,会计凭证)都是系统自动生成,只需要对应的人员进行核查及确认即可,大大降低了工作强度和出错几率。

单据的流程可以根据企业的实际情况定制和修改,可以在系统里面改变工作流程满足企业需求。

具有多语言,多币种,对于贸易类企业OE现有的模块基本可以满足企业90%或更多的应用需求。

虽然是开源软件,Odoo8.0依然是个长期支持的版本,基本每天都有更新,修复各种漏洞,截止2013年已经有200万用户下载了Odoo。成功案例估计成千上万其中不乏美国AT&T ,法国电信,达能集团这样的巨型公司。



请大家点击左上角关注+评论,也欢迎私信跟我交流!

顺便帮忙转发一下

r.actions.client 介绍

ir.actions.client 是odoo actions事件的一种,触发一个在客户端实现(即js文件中定义的函数,通过core.action_registry.add(tag,函数名) 注册到odoo中)动作


  • tag -- action在客户端的标识符,一般是一个专用的字符串,在js文件中注册该动作时指定。
  • params (可选) -- 用来传给客户端动作的,字典格式
  • target (可选) -- current:当前内容区打开action;fullscreen:以全屏模式打开;new:以新窗口打开。
  • context-- 作为额外数据,传递给客户端函数。


实现方式主要有以下几步:

1. 通过继承扩展的方式建立一个m_custome_list.js,里面主要是关联qweb视图,对qweb页面传递数据,渲染视图


在 项目目录/static/src/js 建立 m_custome_list.js 文件

  • m_custome_list.js
odoo.define('custom_page.demo', function (require) {
    "use strict";

 var AbstractAction=require('web.AbstractAction');
 var core=require('web.core');

 var CustomPageDemo=AbstractAction.extend({
 // 对某个类关联click事件
 events: {'click .demo-submit': '_onSubmitClick',
    'click .db_add_data': '_onAddData'},

 // 初始化,可以在action 里传入参数
 init: function (parent, action, option) {
 // 保存传递的参数
    this.params=action.params;
    this._super.apply(this, arguments);
 },

// 渲染视图
 renderElement: function () {
  this._super.apply(this, arguments);
  // 渲染qwb 视图,并传值
  this.$('.o_content').html(
    core.qweb.render('DemoPage', 
         {'params':this.params}));
   },

 _onSubmitClick: function (e) {
   e.stopPropagation();
   alert('Submit clicked!');
 },

// 添加一条数据
_onAddData: (e)=> {
  e.stopPropagation();
  window.alert('添加成功');
 },
});

// add方法对动作进行注册,第一个参数表示注册的动作名,
 第二个参数是要注册的动作对象;
 core.action_registry
   .add('custom_page.demo',CustomPageDemo);

 return CustomPageDemo;

});

2. 编写一个qweb视图,用来承载需要显示的数据样式

在 项目目录/static/src/xml 建立 m_custome_list.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">

  <t t-name="DemoPage">
    <div style="margin:0 auto; 
text-align:center;"class="o_content">
      <table class="table table-striped">
         <tr>
           <th>标题</th>
           <th>内容</th>
           <th>创建日期</th>
          </tr>
          <t t-foreach="params.contentList" t-as="item">
            <tr>
              <td><t t-esc="item.title"/></td>
              <td><t t-esc="item.content"/></td>
              <td><t t-esc="item.date"/></td>
             </tr>
            </t>
      </table>

   <button type="button" 
class="db_add_data btn btn-primary">增加数据</button>
  </div>
</t>

</templates>

3. 在需要显示client的model,调用显示client方法

model 调用client方法, 在model关联的xml视图页面,增加一个按钮,绑定show_list方法,也可以在任何方法中返回client和返回actions.window 一样

def show_list(self):
 content_list=[
  {'title': '内容一', 'content': '我是内容一一,
   在想看看1', 'date': '2021-08-08'},
  {'title': '内容二', 'content': '我是内容二二,
   在想看看2', 'date': '2021-08-09'},
  {'title': '内容三', 'content': '我是内容三三,
   在想看看3', 'date': '2021-08-10'},
  {'title': '内容四', 'content': '我是内容四四,
   在想看看4', 'date': '2021-08-11'},
   ]
  info={
    'title': '测试列表循环',
    'contentList': content_list
   }
  return {
   'type': 'ir.actions.client',
   'name': '列表信息',
   'tag': 'custom_page.demo',
   # custom_page.demo就是前面js中定义的事件名
   'params': info,
   'target': 'new',
 }

4. 加载自己写的m_custome_list.js文件

在 项目目录/views/ 建立 js_and_css.xml 文件, 用来加载自己写的js,别忘了在mainfast.py 中加载这个js_and_css.xml

<?xml version="1.0" encoding="UTF-8"?>
<odoo>
    <template id="assets_end" 
inherit_id="web.assets_backend">
    <xpath expr="." position="inside">
       <script src="/customtree/static/
src/js/m_custome_list.js" 
type="text/javascript"/>
     </xpath>
    </template>
</odoo>

5. 在mainfast.py 中加载自己写的qweb文件 m_custome_list.xml