全书完整目录请见: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来进行用户谁:
- 添加odoo_authenticate.py文件,可以将该文件放在任何位置,因为RPC程序是独立运行的。
- 在该文件中添加如下代码:
1234567891011121314from xmlrpc import clientserver_url = 'http://localhost:8069'db_name = 'test-12'username = 'admin'password = 'admin'common = client.ServerProxy('%s/xmlrpc/2/common' % server_url)user_id = common.authenticate(db_name, username, password, {})if user_id:print("Success: User id is", user_id)else:print("Failed: wrong credentials") - 在终端中使用如下命令来运行这一Python脚本:
1python3 odoo_authenticate.py
如果所提供的为有效的登录名和密码,它会打印成功的消息及用户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()方法的使用示例:
1 2 3 4 5 6 7 |
from xmlrpc import client server_url = 'http://localhost:8069' common = client.ServerProxy('%s/xmlrpc/2/common' % server_url) version_info = common.version() print(version_info) |
前面的程序会给出如下的输出:
TODO
通过XML-RPC搜索/读取记录
在本节中,我们将学习如何通过RPC来从Odoo实例中获取数据。用户可以访问大部分的数据,除受安全权限控制和记录规则所限的数据外。RPC可以在多种场景中使用,如收集数据进行分析、一次操作大量数据或是获邓数据来在另一个软件/系统中展示。有无尽的可用,你可以在任何需要的时候使用RPC。
准备工作
我们将创建一个Python程序来从library.book模型中获取图书数据。请确保已经安装了my_library模块并且服务运行于http://localhost:8069。
如何实现…
执行如下步骤来通过RPC获取图书信息:
- 添加books_data.py文件。可惟将文件放在任意地方,因为RPC程序是独立运行的。
- 在该文件中添加如下代码:
12345678910111213141516171819202122232425from xmlrpc import clientserver_url = 'http://localhost:8069'db_name = 'test-12'username = 'admin'password = 'admin'common = client.ServerProxy('%s/xmlrpc/2/common' % server_url)user_id = common.authenticate(db_name, username, password, {})models = client.ServerProxy('%s/xmlrpc/2/object' % server_url)if user_id:search_domain = ['|', ['name', 'ilike', 'odoo'], ['name', 'ilike', 'sql']]books_ids = models.execute_kw(db_name, user_id, password,'library.book', 'search',[search_domain],{'limit': 5})print('Books ids found:', books_ids)books_data = models.execute_kw(db_name, user_id, password,'library.book', 'read',[books_ids, ['name', 'date_release']])print("Books data:", books_data)else:print('Wrong credentials') - 使用如下命令来在终端中运行这个Python脚本:
1python3 books_data.py
前面的程序将获取到图书数据并给出如下的输出(根据你的数据输出内容可能会不同):
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()方法获取图书数据的替代方式。
它会如同前例一样返回相同的输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
from xmlrpc import client server_url = 'http://localhost:8069' db_name = 'test-12' username = 'admin' password = 'admin' common = client.ServerProxy('%s/xmlrpc/2/common' % server_url) user_id = common.authenticate(db_name, username, password, {}) models = client.ServerProxy('%s/xmlrpc/2/object' % server_url) if user_id: search_domain = ['|', ['name', 'ilike', 'odoo'], ['name', 'ilike', 'sql']] books_ids = models.execute_kw(db_name, user_id, password, 'library.book', 'search_read', [search_domain, ['name', 'date_release']], {'limit': 5}) print('Books data:', books_ids) else: print('Wrong credentials') |
小贴士:即便未请求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创建、写入和更新图书信息:
- 添加books_operation.py文件。你可以该文件放在所希望的任意位置,因为RPC程序将独立运行:
- 在该文件中添加如下代码:
12345678910111213141516171819202122232425262728293031323334353637383940414243from xmlrpc import clientserver_url = 'http://localhost:8069'db_name = 'test-12'username = 'admin'password = 'admin'common = client.ServerProxy('%s/xmlrpc/2/common' % server_url)user_id = common.authenticate(db_name, username, password, {})models = client.ServerProxy('%s/xmlrpc/2/object' % server_url)if user_id:# create new bookscreate_data = [{'name': 'Book 1', 'release_date': '2019-01-26'},{'name': 'Book 3', 'release_date': '2019-02-12'},{'name': 'Book 3', 'release_date': '2019-05-08'},{'name': 'Book 7', 'release_date': '2019-05-14'}]books_ids = models.execute_kw(db_name, user_id, password,'library.book', 'create',[create_data])print("Books created:", books_ids)# Write in existing book recordbook_to_write = books_ids[1] # We will use ids of recently created bookswrite_data = {'name': 'Books 2'}written = models.execute_kw(db_name, user_id, password,'library.book', 'write',[book_to_write, write_data])print("Books written:", written)# Delete the book recordbooks_to_delete = books_ids[2:] # We will use ids ofrecently created booksdeleted = models.execute_kw(db_name, user_id, password,'library.book', 'unlink',[books_to_delete])print('Books unlinked:', deleted)else:print('Wrong credentials') - 通过给出的命令在终端中运行这个Python脚本:
1python3 books_operation.p
前面的程序会创建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。以下是一个展示用户是否具有图书记录创建权限的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
from xmlrpc import client server_url = 'http://localhost:8069' db_name = 'test-12' username = 'admin' password = 'admin' common = client.ServerProxy('%s/xmlrpc/2/common' % server_url) user_id = common.authenticate(db_name, username, password, {}) models = client.ServerProxy('%s/xmlrpc/2/object' % server_url) if user_id: has_access = models.execute_kw(db_name, user_id, password, 'library.book', 'check_access_rights', ['create'], {'raise_exception': False}) print('Has create access on book:', has_access ) else: print('Wrong credentials') # 输出: Has create access on book: True |
通过XML-RPC调用方法
在Odoo中,RPC API并不只限于增删改查操作,你还可以调用业务逻辑。在本节中,我们将调用make_available方法来修改图书的状态。
准备工作
我们将创建一个Python程序来对library.book模型调用make_available。确保你已安装了my_library模块并且服务运行于http://localhost:8069。
如何实现…
执行如下步骤来通过RPC创建、写入及更新图书的信息:
- 添加books_method.py文件。你可以将该文件放在所希望的任何位置,因为RPC程序是独立运行的。
- 在该文件中添加如下代码:
123456789101112131415161718192021222324252627282930from xmlrpc import clientserver_url = 'http://localhost:8069'db_name = 'test-12'username = 'admin'password = 'admin'common = client.ServerProxy('%s/xmlrpc/2/common' % server_url)user_id = common.authenticate(db_name, username, password, {})models = client.ServerProxy('%s/xmlrpc/2/object' % server_url)if user_id:# Create book with state draftbook_id = models.execute_kw(db_name, user_id, password,'library.book', 'create',[{'name': 'New Book', 'date_release': '2019-01-26', 'state': 'draft'}])# Call make_available method on new bookmodels.execute_kw(db_name, user_id, password,'library.book', 'make_available',[[book_id]])# check book status after method callbook_data = models.execute_kw(db_name, user_id, password,'library.book', 'read',[[book_id], ['name', 'state']])print('Book state after method call:', book_data[0]['state'])else:print('Wrong credentials') - 在终端中通过如下命令运行这个Python脚本:
1python3 books_method.py
以上程序会创建一个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进行用户认证:
- 添加jsonrpc_authenticate.py文件。可以把该文件放在任意位置,因为RPC会独立运行。
- 在这个文件中添加如下代码:
12345678910111213141516171819202122232425262728293031323334import jsonimport randomimport requestsserver_url = 'http://localhost:8069'db_name = 'test-12'username = 'admin'password = 'admin'json_endpoint = "%s/jsonrpc" % server_urlheaders = {"Content-Type": "application/json"}def get_json_payload(service, method, *args):return json.dumps({"jsonrpc": "2.0","method": 'call',"params": {"service": service,"method": method,"args": args},"id": random.randint(0, 100000000),})payload = get_json_payload("common", "login", db_name,username, password)response = requests.post(json_endpoint, data=payload,headers=headers)user_id = response.json()['result']if user_id:print("Success: User id is", user_id)else:print("Failed: wrong credentials") - 使用如下命令在终端中运行这个Python脚本:
1python3 jsonrpc_authenticate.py
运行以上程序并传入有效登录名和密码时,该程序会打印一个带有用户 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服务端版本信息的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import json import random import requests server_url = 'http://localhost:8069' json_endpoint = "%s/jsonrpc" % server_url headers = {"Content-Type": "application/json"} def get_json_payload(service, method, *args): ... # see full function definition in last section payload = get_json_payload("common", "version") response = requests.post(json_endpoint, data=payload, headers=headers) print(response.json()) |
这个程序会显示如下输出:
TODO
通过JSON-RPC获取/搜索记录
在前一节中,我们学习了如何通过JSON-RPC来进行认证。本章中,我们将学习如何通过JSON-RPC.来从Odoo实例中获取数据。
准备工作
本节中我将通过JSON-RPC来获取图书信息。确保已安装my_library模块并且服务运行于http://localhost:8069。
如何实现…
执行如下步骤来从library.book模型中获取图书数据:
- 添加jsonrpc_fetch_data.py文件。可以将这个文件放在任意所希望的位置,因为RPC程序将独立运行。
- 在该文件中添加如下代码:
1234567891011121314151617181920# 放置authentication和get_json_payload方法(参见第一个jsonrpc小节)if user_id:# 搜索图书idsearch_domain = ['|', ['name', 'ilike', 'odoo'], ['name', 'ilike', 'sql']]payload = get_json_payload("object", "execute_kw",db_name, user_id, password,'library.book', 'search', [search_domain], {'limit': 5})res = requests.post(json_endpoint, data=payload, headers=headers).json()print('Search Result:', res) # ids will be in result keys# 为图书id 读取数据payload = get_json_payload("object", "execute_kw",db_name, user_id, password,'library.book', 'read', [res['result'], ['name','date_release']])res = requests.post(json_endpoint, data=payload, headers=headers).json()print('Books data:', res)else:print("Failed: wrong credentials") - 通过如下命令在终端中运行这个Python脚本:
1python3 jsonrpc_fetch_data.py
以上程序将返回如下输出。第一个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()来获取图书数据的一种替代方式。它会与前例返回相同的输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 放置authentication和get_json_payload方法(参见第一个jsonrpc小节) if user_id: # 对图书 id 进行搜索和读取 search_domain = ['|', ['name', 'ilike', 'odoo'], ['name', 'ilike', 'sql']] payload = get_json_payload("object", "execute_kw", db_name, user_id, password, 'library.book', 'search_read', [search_domain, ['name', 'date_release']], {'limit': 5}) res = requests.post(json_endpoint, data=payload, headers=headers).json() print('Books data:', res) else: print("Failed: wrong credentials") |
通过JSON-RPC创建/更新/删除记录
在前一小节中我们了解了如何来通过JSON-RPC搜索和读取数据。在本节中,我们将执行通过RPC执行增删改查中剩余的操作 – 创建、更新(写)和删除(unlink)。
准备工作
我们将创建一个Python程序来创建、写入和删除 library.book 模型中的数据。确保已安装了my_library模块并且服务运行于http://localhost:8069。
如何实现…
执行如下步骤来通过RPC创建、写入和删除图书的信息:
- 添加jsonrpc_operation.py文件。可以将该文件放在任意位置,因为RPC程序会独立运行。
- 在文件中添加如下代码:
1234567891011121314151617181920212223242526272829303132333435363738# 放置authentication和get_json_payload方法(参见最后一节获取更多内容)if user_id:# 创建图书记录create_data = [{'name': 'Book 1', 'date_release': '2019-01-26'},{'name': 'Book 3', 'date_release': '2019-02-12'},{'name': 'Book 5', 'date_release': '2019-05-08'},{'name': 'Book 7', 'date_release': '2019-05-14'}]payload = get_json_payload("object", "execute_kw",db_name, user_id, password, 'library.book', 'create',[create_data])res = requests.post(json_endpoint, data=payload,headers=headers).json()print("Books created:", res)books_ids = res['result']# 写入已有图书记录book_to_write = books_ids[1] # 我们将使用新近创建的idwrite_data = {'name': 'Book 2'}payload = get_json_payload("object", "execute_kw",db_name, user_id, password, 'library.book', 'write',[book_to_write, write_data])res = requests.post(json_endpoint, data=payload,headers=headers).json()print("Books written:", res)# 在已有图书记录中进行删除book_to_unlink = books_ids[2:] # 我们将使用新近创建的idpayload = get_json_payload("object", "execute_kw",db_name, user_id, password, 'library.book', 'unlink',[book_to_unlink])res = requests.post(json_endpoint, data=payload, headers=headers).json()print("Books deleted:", res)else:print("Failed: wrong credentials") - 使用如下命令来终端中运行Python脚本:
1python3 jsonrpc_operation.py
以上程序将创建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模型创建操作的权限:
1 2 3 4 5 6 7 8 9 10 |
# 放置authentication和get_json_payload方法(参见上一节获取更多信息) if user_id: payload = get_json_payload("object", "execute_kw", db_name, user_id, password, 'library.book', 'check_access_rights', ['create']) res = requests.post(json_endpoint, data=payload, headers=headers).json() print("Has create access:", res['result']) else: print("Failed: wrong credentials") |
这个程序的输出如下:
TODO
通过JSON-RPC调用方法
在本节中,我们将学习如何通过JSON-RPC调用模型中的自定义方法。我们将通过make_available()方法修改图书的状态。
准备工作
我们将创建Python程序来调用library.book中的make_available方法。确保已安装my_library模块并且服务运行于http://localhost:8069。
如何实现…
执行如下步骤来通过RPC创建、写入及更新图书的信息:
- 添加jsonrpc_method.py文件。你可以把这个文件放在任意位置,因RPC程序将独立运行。
- 在文件中添加如下代码:
1234567891011121314151617181920212223242526# 放置authentication和get_json_payload方法(参见最后一节获取更多信息)if user_id:# 创建draft状态的图书payload = get_json_payload("object", "execute_kw",db_name, user_id, password,'library.book', 'create', [{'name': 'Book 1', 'state': 'draft'}])res = requests.post(json_endpoint, data=payload,headers=headers).json()print("Has create access:", res['result'])book_id = res['result']# 通过调用make_available方法来修改图书状态payload = get_json_payload("object", "execute_kw",db_name, user_id, password,'library.book', 'make_available', [book_id])res = requests.post(json_endpoint, data=payload, headers=headers).json()# 在调用方法后查看图书状态payload = get_json_payload("object", "execute_kw",db_name, user_id, password,'library.book', 'read', [book_id, ['name', 'state']])res = requests.post(json_endpoint, data=payload,headers=headers).json()print("Book state after the method call:", res['result'])else:print("Failed: wrong credentials") - 使用如下命令在终端中运行Python脚本:
1python3 jsonrpc_method.py
以上命令将创建一本状态为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)索引中注册。使用这个库我们需要通过如下命令来安装它。如果需要可在单独的虚拟环境中使用它:
1 |
pip install OdooRPC |
在本节中,我们将使用odoorpc库来进行一些基本操作。我们将使用library.book模型来执行这些操作。确保已安装my_library模型并且服务运行于http://localhost:8069。
如何实现…
执行如下步骤来通过RPC创建、写入并更新图书的信息:
- 添加odoorpc_library.py文件。你们可以将文件放在任意位置,因为RPC程序将独立运行。
- 在该文件中添加如下代码:
1234567891011121314151617181920212223242526272829import odoorpcdb_name = 'test-12'user_name = 'admin'password = 'admin'# 准备对服务端的连接odoo = odoorpc.ODOO('localhost', port=8069)odoo.login(db_name, user_name, password) # login# 用户信息user = odoo.env.userprint(user.name) # name of the user connectedprint(user.company_id.name) # the name of user's companyprint(user.email) # the email of usserBookModel = odoo.env['library.book']search_domain = ['|', ['name', 'ilike', 'odoo'], ['name', 'ilike', 'sql']]books_ids = BookModel.search(search_domain, limit=5)for book in BookModel.browse(books_ids):print(book.name, book.date_release)# create the book and update the statebook_id = BookModel.create({'name': 'Test book', 'state': 'draft'})print("Book state before make_available:", book.state)book = BookModel.browse(book_id)book.make_available()book = BookModel.browse(book_id)print("Book state before make_available:", book.state) - 使用如下命令来终端中运行这个Python脚本:
1python3 odoorpc_library.py
该程序会进行验证、打印用户信息并在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语法中读取图书信息的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import odoorpc db_name = 'test-12' user_name = 'admin' password = 'admin' # 准备对服务端的连接 odoo = odoorpc.ODOO('localhost', port=8069) odoo.login(db_name, user_name, password) # login books_info = odoo.execute('library.book', 'search_read', [['name', 'ilike', 'odoo']], ['name', 'date_release']) print(books_info) |
其它内容
有一些针对Odoo的RPC库的其它实现,如下: