Odoo 12开发者指南第二十章 Odoo中的远程过程调用(RPC)

Odoo Alan 5年前 (2019-05-19) 6538次浏览 2个评论 扫描二维码

全书完整目录请见:Odoo 12开发者指南(Cookbook)第三版

Odoo服务支持远程过程调用(RPC),即你可以在外部应用中连接Odoo实例。通过Odoo RPC API,你可以对数据库执行任意增删改查(CRUD)操作。 Odoo RPC不只是可以执行增删改查操作,还可以调用任意模型中的公共方法。当做,你需要相应的访问权限来执行这些操作,因为RPC遵循你在数据库中定义的所有访问权限和记录规则。因此,使用起来非常安全。Odoo RPC不依赖于平台,你可以在任何平台上使用,包含Odoo.sh、线上或自托管平台。Odoo RPC可用于任一编程语言,因此你可以将Odoo集成到任何外部应用中。

Odoo提供了两种类型的RPC API – XML-RPC 和 JSON-RPC。本章中,我们将学习如何在外部程序中使用这些RPC。最后,你会学到如何通过OCA的odoorpc库使用Odoo RPC。

本章中,我们将讲解如下内容:

  • 通过XML-RPC登录/连接Odoo
  • 通过XML-RPC搜索/读取记录
  • 通过XML-RPC创建/更新/删除记录
  • 通过XML-RPC调用方法
  • 通过JSON-RPC登录/连接Odoo
  • 通过JSON-RPC获取/搜索记录
  • 通过JSON-RPC创建/更新/删除记录
  • 通过JSON-RPC调用方法
  • OCA odoorpc库

技术准备

本章中我们将使用第十九章 使用Odoo.sh管理、部署和测试中所创建的my_library模块。初始的my_library模块代码请见GitHub仓库:https://github.com/PacktPublishing/Odoo-12-Development-Cookbook-Third-Edition/tree/master/Chapter20/r0_initial_module。

这里我们不会介绍读者可能熟悉的新语言。我们会继续使用Python来访问RPC API。如果愿意你可以使用其它语言,这里访问RPC的流程同样适用于其它语言。

通过RPC连接Odoo,我们将需要运行Odoo实例来供连接。整章中我们都将假设你的Odoo服务运行于http://localhost:8069且安装了my_library模块的数据库名称为test-12。注意你其实可以通过RPC连接任意有效IP或域名。

通过XML-RPC登录/连接Odoo

在本节中,我们将通过RPC来进行用户验证以检测所提供的认证信息是否有效。

准备工作

要通过RPC连接Odoo实例,你需要运行Odoo实例来供连接。我们将假定你的Odoo服务运行于http://localhost:8069并且已安装了my_library模块。

如何实现…

执行如下步骤来通过RPC来进行用户谁:

  1. 添加odoo_authenticate.py文件,可以将该文件放在任何位置,因为RPC程序是独立运行的。
  2. 在该文件中添加如下代码:
  3. 在终端中使用如下命令来运行这一Python脚本:

如果所提供的为有效的登录名和密码,它会打印成功的消息及用户ID。

运行原理…

本节中,我们使用了Python的xmlrpc 库来通过XML-RPC访问Odoo实例。这是一个Python标准库,你无需进行任何安装即可使用它。

Odoo在/xmlrpc/2/common端点上提供了ML-RPC来进行验证操作。该端点用于无需进行谁的元方法。authentication() 方法本身是一个公有方法,因此可在外部调用。Authentication方法可接收4个参数:数据库名、用户名、密码以及user agent环境。user agent环境是必传的参数,但如果你想要传入user agent参数,请至少传递一个空字典。

在执行带有所有有效参数的authenticate() 方法时,它会调用Odoo服务并执行认证。然后如果所给定的登录ID和密码正确的话会返回用户ID。如果用户不存在或是密码错误的话会返回False。

你需要在通过RPC访问数据之前使用authenticate方法。这是因为使用错误的认证信息访问数据的话会产生报错。此外,用于访问数据的方法要求传入用户ID而不是用户名,因此也需要使用authenticate方法来获取用户的ID。

小贴士:Odoo的在线实例 (*.odoo.com)使用OAuth认证,因此本地密码并没有在实例中进行设置。要对这些实例使用XML-RPC,你将需要在实例的Settings > Users > Users菜单中手动设置用户的密码。

扩展知识…

/xmlrpc/2/common端点提供有另一个方法:version()。调用该方法可以无需认证信息。它会返回Odoo实例的版本信息。以下是version()方法的使用示例:

前面的程序会给出如下的输出:

TODO

通过XML-RPC搜索/读取记录

在本节中,我们将学习如何通过RPC来从Odoo实例中获取数据。用户可以访问大部分的数据,除受安全权限控制和记录规则所限的数据外。RPC可以在多种场景中使用,如收集数据进行分析、一次操作大量数据或是获邓数据来在另一个软件/系统中展示。有无尽的可用,你可以在任何需要的时候使用RPC。

准备工作

我们将创建一个Python程序来从library.book模型中获取图书数据。请确保已经安装了my_library模块并且服务运行于http://localhost:8069。

如何实现…

执行如下步骤来通过RPC获取图书信息:

  1. 添加books_data.py文件。可惟将文件放在任意地方,因为RPC程序是独立运行的。
  2. 在该文件中添加如下代码:
  3.  使用如下命令来在终端中运行这个Python脚本:

前面的程序将获取到图书数据并给出如下的输出(根据你的数据输出内容可能会不同):

TODO

运行原理…

要访问图书数据,首先要执行验证。在程序的开头处我们以通过XML-RPC登录/连接Odoo一节中相同的方式进行了验证。如果你提供了有效认证信息,认证方法会返回用户记录的id。我们将使用这个用户ID来获取图书数据。

/xmlrpc/2/object端点用于数据库操作。在本节中,我们使用了object端点来获取图书数据。对比 /xmlrpc/2/common端点,这个端点在没有认证信息时无法使用。借助这个端点,我们通过execute_kw()可以访问任意模型的对公方法,execute_kw接收如下参数:

  • 数据库名
  • 用户 ID(从authenticate方法中获取)
  • 密码
  • 模型名,如res.partner, library.book
  • 方法名,如search, read, create
  • 一个位置参数数组
  • 一个关键字参数的字典(可选)

在示例中,我们希望获取图书的信息。这可通过search()和read()的组合来实现。图书信息存储于library.book模型中,因此在execute_kw()中我们使用library.book 作为模型名、search作为方法名。这会调用ORM的搜索方法并返回记录ID。这里唯一的不同是ORM的搜索方法返回一个记录集,而这个search方法返回一个ID列表。

在execute_kw()中,你可以向所提供方法传递参数和关键字参数。search()方法接收一个域作为位置参数,通过传递域来过滤图书。搜索方法还有其它的可选关键字参数,如 limit, offset, count和order,我们使用了limit参数来仅获取5条记录。这会返回一个图书ID列表,名称中包含odoo或SQL字符串。我们还需要从数据库中获取图书数据。我们将使用read方法来完成这一操作。read方法接收一个ID和字段列表来完成这一任务。在第3步中的最后,我们使用了通过搜索方法接收到的图书ID列表,然后使用这些图书ID来获取图书的name和release_date。这会返回一个带有图书信息的字典列表。

ℹ️注意传递给execute_kw()的参数和关键字参数基于所传递的方法。你可以通过execute_kw().使用任意对公的ORM方法。仅需给出方法名、有效参数和关键字参数。这些参数将被传递到ORM的方法中。

扩展知识…

通过search()和read()方法合并的获取的数据颇为耗时,因为它进行了两次调用, search_read是获取同样数据的一个替代方法。你可以在单次调用中同时搜索并获取数据。下面是使用search_read()方法获取图书数据的替代方式。

它会如同前例一样返回相同的输出:

小贴士:即便未请求id字段,read和search_read方法也会返回id字段。此外对于many2one字段,我们将获取一个由id和显示名称组成的数组。例如,create_uid many2one字段将返回类似这样的结果: [12, ‘Parth Gajjar’]。

通过XML-RPC创建/更新/删除记录

在前一节中,我们学习了如何通过RPC搜索和读取数据。本节中我们通过RPC将执行增删改查(CRUD)中余下的操作,即创建、更新(write)和删除(unlink)。

准备工作

我们将创建Python程序来对 library.book模型创建、写入和删除数据。确保已安装了my_library并且服务运行于http://localhost:8069。

如何实现…

执行如下步骤来通过RPC创建、写入和更新图书信息:

  1. 添加books_operation.py文件。你可以该文件放在所希望的任意位置,因为RPC程序将独立运行:
  2. 在该文件中添加如下代码:
  3. 通过给出的命令在终端中运行这个Python脚本:

前面的程序会创建4条图书记录。在图书记录中更新数据并在此后删除两条记录,输出如下(根据你的数据库所创建的ID可能会不同):

TODO

运行原理…

在本节中,我们通过XML-RPC.执行了create, write和delete操作。这个操作还使用了/xmlrpc/2/object端点及execute_kw方法。

从Odoo v12开始, create()方法支持在单个调用中创建多条记录。在第2步中,我们首先创建了一个带有图书信息的字典。然后我们使用了图书的字典来通过XML-RPC新建了图书记录。XML-RPC调用需要两个参数来创建新记录 – create方法名及图书数据。这会在library.book模型中创建4条图书记录。在ORM中,我们在创建记录时,它返回一个所创建记录的记录集,但如果通过RPC创建记录,它会返回一个ID列表。

write方法与create方法运行的方式相似。在write方法中,你将需要传递一个记录ID及字段值列表来进行写入。在本例中,我们更新了在第一部分所创建的图书的名称。这会将第二本图书的名称从Book 3更新为Book 2。这里我们仅传递了图书的一个id,但如果想要在单个调用中更新多条记录的话也可以传递ID列表。

在这个程序的第3部分中,我们删除了两条在第1部分中所创建的图书。可以通过unlink方式及记录ID列表来删除记录。

在程序成功执行之后,在数据库中可以看到两条图书记录。

扩展知识…

在通过RPC执行增删改查操作时,它可能会在没有执行该操作权限时产生报错。通过check_access_rights方法,你可以检测该用是否有执行某一操作的相应权限。check_access_rights方法根据用户的访问权限返回True或False。以下是一个展示用户是否具有图书记录创建权限的示例:

通过XML-RPC调用方法

在Odoo中,RPC API并不只限于增删改查操作,你还可以调用业务逻辑。在本节中,我们将调用make_available方法来修改图书的状态。

准备工作

我们将创建一个Python程序来对library.book模型调用make_available。确保你已安装了my_library模块并且服务运行于http://localhost:8069。

如何实现…

执行如下步骤来通过RPC创建、写入及更新图书的信息:

  1. 添加books_method.py文件。你可以将该文件放在所希望的任何位置,因为RPC程序是独立运行的。
  2. 在该文件中添加如下代码:
  3. 在终端中通过如下命令运行这个Python脚本:

以上程序会创建一个draft状态的图书,然后通过调用make_available方法来修改图书的状态。然后,我们将获取到图书的数据来查看图书状态,它将会给出如下的输出:

TODO

运行原理…

可以通过RPC调用任意模型方法。这有助于我们执行业务逻辑却又不陷入负面效果。例如,我们通过RPC创建了销售订单,然后调用于sale.order 的action_confirm方法。这等价于在销售订单表单中点击Confirm按钮。

你可以调用任意模型的任意公有方法,但无法通过RPC调用私有方法。以_开头的方法名称之为私有方法,如_get_share_url()和_get_data()。

使用这些方法是安全的,因为它们经过ORM并遵循所有的安全规则。如果该方法访问了未授权的记录,则会产生错误。

在示例中,我们创建了一个状态为draft的图书。然后我们再次进行了RPC调用来调用make_available方法,这会将该书的状态修改为available。最后,我们又进行了一次RPC调用来查看图书的状态。它会显示图书的状态已修改为available。

ℹ️没有内部返回内容的方法默认返回None。这种方法不能通过RPC来使用。因此,如果你希望通过RPC使用自己的方法,至少请添加 return True语句。

扩展知识…

如果通过方法产生了异常,所有在事务中执行的操作会自动回滚到初始状态。这仅适用于单个事务(单个RPC调用)。例如,设想一下你对服务端做了两次RPC调用并且在第二次调用时产生了异常。这会在第二次RPC调用中对执行的操作进行回滚。通过第一个RPC调用所执行的操作并不会进行回滚。因此,你需要通过RPC执行一个复杂的操作。推荐通过模型中的方法在单个RPC调用中执行它

通过JSON-RPC登录/连接Odoo

Odoo还提供另一种类型的RPC API: JSON-RPC。由名称可知,JSON-RPC以JSON格式来进行操作并使用 jsonrpc 2.0规范。本节中,我们将学习如何使用JSON-RPC来进行登录。Odoo网页客户端本身使用JSON-RPC来从服务端获取数据。

准备工作

本节中,我们将通过JSON-RPC 来执行用户认证来检查给定的认证信息是否有效。确保已安装了my_library模块并且服务运行于http://localhost:8069。

如何实现…

执行如下步骤来通过RPC进行用户认证:

  1. 添加jsonrpc_authenticate.py文件。可以把该文件放在任意位置,因为RPC会独立运行。
  2. 在这个文件中添加如下代码:
  3. 使用如下命令在终端中运行这个Python脚本:

运行以上程序并传入有效登录名和密码时,该程序会打印一个带有用户 id 的成功消息,如下:

TODO

运行原理…

JSON-RPC使用JSON格式来与服务端通讯。它使用/jsonrpc端点来与服务端通讯。在本例中,我们使用了Python的requests包来进行POST请求,但如果你希望的话,也可以使用其它包,如urllib。

JSON-RPC仅接收按照JSON-RPC 2.0规范格式的数据,参见https://www.jsonrpc.org/specification来学习有关JSON-RPC格式的更多知识。在本例中,我们创建了 get_json_payload()方法。该方法将以有效的JSON-RPC 2.0格式准备加载数据。这个方法接收服务名和要调用的方法,并且剩余的参数将会放在*args中。我们将在后续的小节中使用这一方法。JSON-RPC接收JSON格式的请求并且这些请求仅接收包含{“Content-Type”: “application/json”}头的请求。请求的结果为JSON格式。

类似XML-RPC,所有的公有方法,包含login,都在common服务下。出于这一原因,我们传递了common作为服务以及login作为方法来准备JSON加载数据。login方法要求一些额外的参数,因此我们传递了数据库名、用户名和密码。然后我们使用加载数据和头信息对这个JSON端点进行了POST请求。如果你传递了正确的用户名和密码,该方法返回用户 id。响应将为JSON格式并且你会在result键中获取到结果。

ℹ️注意本节中创建的get_json_payload()方法用于从示例中删除重复代码。并非必须使用它,可以应用你自己的调整。

扩展知识…

类似XML-RPC,version方法也可在JSON-RPC中使用。JSON-RPC方法在common服务中并且可对外进行访问。无需登录信息即可获取到版本信息。查看如下展示如何获取Odoo服务端版本信息的示例:

这个程序会显示如下输出:

TODO

通过JSON-RPC获取/搜索记录

在前一节中,我们学习了如何通过JSON-RPC来进行认证。本章中,我们将学习如何通过JSON-RPC.来从Odoo实例中获取数据。

准备工作

本节中我将通过JSON-RPC来获取图书信息。确保已安装my_library模块并且服务运行于http://localhost:8069。

如何实现…

执行如下步骤来从library.book模型中获取图书数据:

  1. 添加jsonrpc_fetch_data.py文件。可以将这个文件放在任意所希望的位置,因为RPC程序将独立运行。
  2. 在该文件中添加如下代码:
  3. 通过如下命令在终端中运行这个Python脚本:

以上程序将返回如下输出。第一个RPC调用会打印图书的id并且第二个会打印针对图书id的信息:

TODO

运行原理…

通过JSON-RPC登录/连接Odoo一节中,我们学习到可以进行用户名密码的验证。如果登录的详情都正确的话,RPC调用会返回user_id。然后你可以使用这个user_id来获取模型数据。类似XMLRPC,我们需要使用search和read组合来从模型中获取数据。要获取数据,我们使用object来作为服务、execute_kw来作为方法,execute_kw与我们用XML-RPC获取数据时使用的是同一个方法,因此它也接收相同的参数,如下:

  • 数据库名
  • 用户 ID(从authenticate方法中获取)
  • 密码
  • 模型名,如res.partner, library.book
  • 方法名,如search, read, create
  • 一个位置参数数组(args)
  • 一个关键字参数的字典(可选)(kwargs)

在本例中,我们首先调用了search方法。execute_kw方法通常接收必选参数来作为位置参数、可选参数来作为关键字参数。在搜索方法中,domain是必选参数,因此我们在列表中进行传递并传递了可选参数limit来作为关键字参数(字典)。你将获取到一个JSON格式的响应,并且在本节中search()方法RPC的响应会在result键中包含图书的ID。

在第2步中,我们通过read方法作了一个RPC调用。为读取图书的信息,我们传递了两个位置参数:图书ID列表和要获取字段的列表。这个RPC调用将以JSON格式返回图书信息并且你可以在result键中访问它。

ℹ️除execute_kw外,你还可以使用execute来作为方法。它不支持关键字参数,因此如果想要传递一些可选参数的话你需要传递所有的中间参数。

扩展知识…

类似于XML-RPC,你可以使用search_read()方法来代替 search() 和 read()方法的组合,因为那样耗时会略多。以下是通过search_read()来获取图书数据的一种替代方式。它会与前例返回相同的输出:

通过JSON-RPC创建/更新/删除记录

在前一小节中我们了解了如何来通过JSON-RPC搜索和读取数据。在本节中,我们将执行通过RPC执行增删改查中剩余的操作 – 创建、更新(写)和删除(unlink)。

准备工作

我们将创建一个Python程序来创建、写入和删除 library.book 模型中的数据。确保已安装了my_library模块并且服务运行于http://localhost:8069。

如何实现…

执行如下步骤来通过RPC创建、写入和删除图书的信息:

  1. 添加jsonrpc_operation.py文件。可以将该文件放在任意位置,因为RPC程序会独立运行。
  2. 在文件中添加如下代码:
  3. 使用如下命令来终端中运行Python脚本:

以上程序将创建4本书。写入一本书并删除两本书将得到如下输出(根据你的数据库所创建的 ID 可能会不同):

TODO

运行原理…

execute_kw用于创建、更新和删除的操作。从Odoo 12开始,create方法支持创建多条记录。因此我们准备了带有4本书信息的字典。然后我们通过library.book作为模型名、create作为方法名进行了JSON-RPC调用。它会在数据库中创建4条图书记录并返回带有这个新建图书 ID 的JSON响应。在下一个RPC调用中,我们希望使用这些 ID 来进行RPC调用来进行更新和删除操作,因此我们将其分配给了books_ids变量。

ℹ️JSON-RPC和XML-RPC 在未对必填字段提供值而尝试创建记录时产生报错,因此确保在create的值中添加了所有必填字段。

在下一个RPC调用中,我们使用了write方法来更新已有记录。write方法接收两个位置参数:待更新的记录和要写入的值。在本例中,我们通过使用所创建图书 ID的第二本书的 ID更新了书名。这会将第二本书的书名由Book 3修改为Book 2。

然后我们进行了删除两本图书记录的RPC调用。执行这一操作我们使用了unlink方法。unlink方法仅接收一个参数,我们希望删除的记录ID。这个RPC调用将删除最后两本图书。

扩展知识…

类似XML-RPC,你可以在 JSON-RPC中使用check_access_rights来检测是否有执行这一操作的权限。这个方法要求有两个参数 – 模型名和操作名。在下例中,我们查看对library.book模型创建操作的权限:

这个程序的输出如下:

TODO

通过JSON-RPC调用方法

在本节中,我们将学习如何通过JSON-RPC调用模型中的自定义方法。我们将通过make_available()方法修改图书的状态。

准备工作

我们将创建Python程序来调用library.book中的make_available方法。确保已安装my_library模块并且服务运行于http://localhost:8069。

如何实现…

执行如下步骤来通过RPC创建、写入及更新图书的信息:

  1. 添加jsonrpc_method.py文件。你可以把这个文件放在任意位置,因RPC程序将独立运行。
  2. 在文件中添加如下代码:
  3. 使用如下命令在终端中运行Python脚本:

以上命令将创建一本状态为draft的图书,然后我们通过调用make_available方法修改图书的状态。此后,我将获取图书数据来检查图书的状态,输出如下:

TODO

运行原理…

execute_kw能够调用模型中的任意公有方法。如我们在通过XML-RPC调用方法一节中所看到的,公有方法是那些方法名不以 _ (下划线)开头的方法。以 _ 开头的为私有方法,不可通过JSON-RPC进行调用。

在我们的示例中,我们创建了状态为draft的图书。然后再进行了RPC调用来调用make_available方法,它将修改图书的状态为available。最后,我们再次使用RPC调用来检查图书的状态。它会显示图书的状态修改为available。

ℹ️注意内部没有返回任何内容的方法默认返回None。这种方法无法通过RPC使用。如果你希望在RPC中使用自己的方法,至少应添加return True语句。

OCA odoorpc库

Odoo社区联盟(OCA)提供名为odoorpc的Python库。可通过https://github.com/OCA/odoorpc进行获取。odoorpc库提供一种用户友好的语法,使用它可以通过RPC访问Odoo数据。它提供一种类似于后端服务的语法。在本节中,我们将学习如何使用odoorpc库来通过RPC执行操作。

准备工作

odoorpc库在Python包(PyPi)索引中注册。使用这个库我们需要通过如下命令来安装它。如果需要可在单独的虚拟环境中使用它:

在本节中,我们将使用odoorpc库来进行一些基本操作。我们将使用library.book模型来执行这些操作。确保已安装my_library模型并且服务运行于http://localhost:8069。

如何实现…

执行如下步骤来通过RPC创建、写入并更新图书的信息:

  1. 添加odoorpc_library.py文件。你们可以将文件放在任意位置,因为RPC程序将独立运行。
  2. 在该文件中添加如下代码:
  3. 使用如下命令来终端中运行这个Python脚本:

该程序会进行验证、打印用户信息并在library.book 模型中执行操作。它会生成如下输出:

TODO

运行原理…

在安装了odoorpc库之后,我们就可以直接使用它了。使用时需要导入odoorpc包,然后我们通过传递服务端URL和端口来创建ODOO类的对象。它会对服务端进行/version_info调用来检查连接。要登录,需要使用该对象的 login()方法。此处,我们需要传递数据库名、用户名和密码。

成功登录后,可以使用odoo.env.user访问用户信息。odoorpc提供一种用户友好的RPC版本,我们可以完全像服务端的记录集一样使用这个用户对象。在示例中,我们从用户对象中访问了姓名、邮箱和公司名。

如果想要访问模型仓库,可以使用odoo.env对象。我们可以调用模型中的任意模型方法。底层odoorpc库使用jsonrpc,因此我们无法调用以 _ 开头的私有模型方法。在本例中,我们从仓库中访问了library.book模型。然后中,我们调用于了带有domain和limit参数的search方法。它会返回图书的ID。通过对browse()方法传递图书ID,我们可以为library.book模型生成一个记录集。在程序的结束处,我们新建了一本图书并通过调用make_available()方法修改了图书的状态。如果仔细查看程序的语法,你会看到它使用了和服务端相同的语法。

扩展知识…

虽然它像服务端一样提供了用户友好的语法,但你可以用普通RP同样的语法使用这个库。我们需要使用带有模型名、方法名和参数的odoo.execute方法来进行实现。以下是在原生RPC语法中读取图书信息的示例:

其它内容

有一些针对Odoo的RPC库的其它实现,如下:

喜欢 (5)
[]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(2)个小伙伴在吐槽
  1. 请问一下使用odoorpc库安全吗?因为公司其他系统跟odoo对接用的rpc,有些信息属于机密,不知道会不会有泄露的危险
    grey272019-08-31 19:35 回复
    • Alan
      这方面我并没有深入的研究,但试着回答下。首先 Odoo 已提供了安全规则和验证的机制,其次如果贵司信息为机密,那么想必已有相应级别的安全策略,Odoo 作为一种 Web 应用,所有的安全策略同样适用于它。比如完全可以限制指定 IP 访问甚至只运行于公司内网中。
      Alan2019-08-31 20:52 回复