Odoo

Odoo 对象

一切都是对象

OpenERP 的所有资源(Resource)都是对象,如 menus, actions, reports, invoices, partners 等等。 换言之,在 OpenERP 中,一个菜单项,一个弹出窗口,其实都是一条数据库记录。OpenERP 运行 时,从数据库读出“菜单项”记录,根据该记录 的信息,在屏幕上显示菜单项及其子菜单项。因此,理 论上,可以不写代码,而是直接修改 OpenERP 的数据库而编写功能菜单、查询窗口、动作按钮等实 现业 务功能开发。实际开发中,通常是编写 XML 文件,导入菜单、窗口、动作等编程元素,实现功 能开发。XML 文件比直接修改数据库或编写 SQL 语句更容易使用 一些。

OpenERP 通过自身实现的对象关系映射(ORM,object relational mapping of a database)访问数据 库。OpenERP 的对象名是层次结构的,就是说可以使用"."访问树状对象,如: ·account.invoice : 表示财务凭证对象。 ·account.invoice.line : 表示财务凭证对象中的一个明细行对象。

通常,对象名中,第一级是模块名,如: account, stock, sale 等。比之直接用 SQL 访问数据库, OpenERP 的对象的优势有,

  1. 直接使用对象的方法增、删、改数据库记录。因为 OpenERP 在基类 对象中实现了常 规的增、删、改方法,因而,普通对象中不需要写任何方法和代码就具备增、删、改 数据库记录的功能。

  2. 对于复杂对象,只需操作一个对象即可访问多张数据 表。如 partner 对象,它 的信息实际上存储在多张数据表中(partner address, categories, events 等等),但只要通过"."操作即 可访问所有关联表(如,partner.address.city),简化了数据库访问。

注意,在其他编程语言或开发平台(如 Java or JavaEE)中,一个对象(Object)通常和数据库中一条 记录(Record)相对应。但是,OpenERP 的对象其实是一个 Class,它和一个 数据表(Table)对应,而 不是和一个记录(Record)对应。在 OpenERP 中,数据库记录(Record)通常叫资源(Resource)。因 为 Object 操作的是数据表,OpenERP 的对象的方法(Method)中,几乎每个方法都带有参数 ids,该参数 是资源(Resource or Record)的 ID(在 OpenERP 中 ID 是主键)列表,通过该 ids 就可以操作具体的 Record 了。

访问 OpenERP 对象

OpenERP 提供了三种方式执行对象的方法(Method),每种方式都是先取得对象,然后调用对象 的方法。三种方式是,

  1. 直接使用对象

  2. 通过 netservice 使用对象

  3. 通过 xmlrpc 使用对象。

直接使用对象

这种方式最简单,这种方式只能在 OpenERP Server 端使用,编写 OpenERP 的 模块时候,通常使用这种方式。这个方式的内部实现原理是,OpenERP 加载模块(不是安装,是启动 时加载已安 装模块)时,会将创建模块中的对象实例,对象实例以对象名为关键字,存储在对象池 (pool)中。此方式是,从 pool 中取得对象,而后调用对象的方法。

这个方式的一般调用形式是:

obj=self.pool.get('name_of_the_object')
obj.name_of_the_method(parameters_for_that_method)

第一行代码从对象池中取得对象实例,第二行代码调用对象的方法。

Netservice 方式

这个方式和直接使用对象的方式是类似的,只是不以对象的方式呈现,而是以 “服务”(Service)的方式呈现。这种方式也只能在 OpenERP Server 端使用,即调用程序和 OpenERP Server 程序在同一个 Python 虚拟机上运行。这个方式的内部实现原理是,类似对象池,OpenERP 有一个全局变量的服务池:SERVICES, 该变量位于 bin\netsvc.py。有一些对象,它在创建时 (__init__方法中)将自己提供的服务登记在服务池中,并暴露自己的服务方法(即该 服务可供调用的method)。和对象池不同的是,服务可以有选择性的暴露自己的方法。OpenERP 的工作流(Workflow)、 报表 (Report)都以服务的形式暴露自己的方法,关于 OpenERP 可供使用的服务有哪些,将在以后介 绍。这个方式调用形式如下:

service = netsvc.LocalService("object_proxy")
result = service.execute(user_id, object_name, method_name, parameters)

第一行指定服务名取得服务,"object_proxy"是 osv.osv 对象初始化时注册的一个服务,这个服 务可用于调用 OpenERP 的几乎所有对象 (准确的说是所有从 osv.osv 派生的对象)。"object_proxy"服 务用于调用对象的方法。第二行是其调用格式,execute 是该服务暴露 的一个服务方法, 该方法的参数说明如下:

  • user_id: 用户 id,以用户名、密码登录后取得的 id。
  • object_name: 对象名,欲访问的对象的名称,如"res.patner"等。
  • method_name: 方法名,欲调用的方法的名称,如"create"等。
  • parameters: 方法的参数。

XML−RPC 方式

这个方式相当灵活,它以 HTTP 协议远程访问对象,因此,能在本机、局域网、 广域网范围调用 OpenERP 的对象的方法。该方式的调用形式是:


sock = xmlrpclib.ServerProxy('http://server_address:port_number/xmlrpc/object')
result = sock.execute(user_id, password, object_name, method_name, parameters)

参数说明如下:

  • server_address: 运行 OpenERP Server 的机器的 IP 或域名。
  • port_number: OpenERP Server 的 xmlrpc 调用端口,缺省情况是 8069。
  • execute 的参数和 Netservice 方式相同,只是多了个 password 参数,该参数即用户的登录密码。

XML-RPC 方式参考例子。这个例子以 xmlrpc 方式调用 OpenERP 的对象 res.partner,在数据库 中插入一条业务伙伴及其联系地址记录。因为含有中文,测试时注意代码文件保存成 utf-8 格式:

import xmlrpclib #导入 xmlrpc 库,这个库是 python 的标准库。
username ='admin' #用户登录名
pwd = '123' #用户的登录密码,测试时请换成自己的密码
dbname = 'case1' #数据库帐套名,测试时请换成自己的帐套名
# 第一步,取得 uid
sock_common = xmlrpclib.ServerProxy ('http://localhost:8069/xmlrpc/common')
uid = sock_common.login(dbname, username, pwd)
#replace localhost with the address of the server
sock = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/object')
# 调用 res.partner 对象的 create 方法在数据库中插入一个业务伙伴
partner = {
'name': 'shine-it',
'lang': 'zh_CN',
}
 partner_id = sock.execute(dbname, uid, pwd, 'res.partner', 'create', partner)
开源智造咨询有限公司(OSCG) - OpenERP 7.0 开发教程 参考: Document Reference 版本 Draft
页 21/56# 下面再创建业务伙伴的联系地址记录
address = {
'partner_id': partner_id,
'type' : 'default',
'street': '浦东大道 400 号',
'zip': '200000',
'city': '上海市',
'phone': '021-88888888',
}

address_id = sock.execute(dbname, uid, pwd, 'res.partner.address', 'create', address)

再议 OPENERP 的对象

通过上面的解说,可以 这样通俗的理解 OpenERP 的对象:

每个对象就是一个代码块,包含了数据表操作(增删改查)的代码。OpenERP Server 好比是一个 代码池,里面装满了代码块。

通过对象池、服务池、xmlrpc 等方式,可以取得代码块位置(或者专业 一点,叫指针),然后调用代码块的方法,操作数据库。对象的代码什么时候装入“代码池”呢?每个对 象定义的后面都有一行:name_of_the_object(),这一行实际上是创建对象实例,实例创建好以后就 装到了代码池,这个装入的过程在对象的基类(osv.osv)中完成。

对象的基类(osv.osv)已实现了增删改 查等常规数据表操作方法,因此,只要定义好对象的字段,即使不写任何代码,该对象已经具备增删 改查数据表的能力。