【odoo14】第二十章、odoo的远程过程调用

odoo支持远程过程调用(RPC),你可以通过其他的应用连接odoo的实例。比如,我们可以通过使用java编写的android应用连接odoo实例展示过期的订单信息。通过odoo的RPC API,我们可以操作数据库的CURD。odoo的RPC不仅仅局限于数据库的CURD,还支持对象的方法调用。odoo的RPC依然适用于odoo内部的权限管理机制。odoo的RPC适用于任意平台、任意语言调用。
odoo提供了两种类型RPC,XML-RPC和JSON-RPC。本章,我们将学习如何使用RPC。最后,我们将使用OCA的odoorpc包实现odoo的RPC调用。
本章内容如下:

  1. 通过XML-RPC实现登录odoo
    2. 通过XML-RPC获取和读取数据(未完成)
    3. 通过XML-RPC创建、更新、删除数据(未完成)
    4. 通过XML-RPC调用函数(未完成)
  2. 通过JSON-RPC登录odoo
    6. 通过JSON-RPC过滤及搜索数据
    7. 通过JSON-RPC创建、更新、删除数据
    8. 通过JSON-RPC调用函数
  3. OCA的odoorpc库(超好用)
  4. 生成API key

技术需求

本章,我们将使用第十九章的my_library模块。可见GitHub repository: https://github.com/ PacktPublishing/Odoo-12-Development-Cookbook-Third-Edition/tree/master/Chapter19/r0_initial_module.

假设你已经有一个在运行的odoo实例,http://localhost:8069,使用名为book-db-14的数据库,安装了名为my_library的模块。

通过XML-RPC实现登录odoo

本节,我们通过RPC实现用户验证并检查用户凭证是否有效。

准备

步骤

  1. 添加odoo_authenticate.py文件,放在哪里随意。
  2. 添加代码
from xmlrpc import client

server_url = "http://localhost:8069"
db_name = "book-db-14"
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")
  1. 运行文件
python3 odoo_authenticate.py

原理

本节,我们通过python的xmlrpc包实现访问odoo实例。这是python自带的标准包,不用额外安装。

odoo提供/xmlrpc/2/common节点用于XML-RPC调用。此端点用于不需要身份验证的元方法。authentication()方法本身是一个公共方法,因此可以公开调用它。authentication()方法接受四个参数——数据库名称、用户名、密码和用户代理环境。用户代理环境是一个强制参数,但是如果您不想传递用户代理参数,至少要传递空字典。

当您使用所有有效参数执行authenticate()方法时,它将调用Odoo服务器并执行身份验证。然后,如果给定的登录ID和密码是正确的,它将返回用户ID。如果用户不存在或者密码不正确,则返回False。

在通过RPC访问任何数据之前,您需要使用authenticate()方法。这是因为使用错误的凭据访问数据将产生错误。

小贴士
Odoo的在线实例(*.odoo.com)使用OAuth认证,
因此,本地密码没有在实例上设置。要在这些实例上使用XML-RPC,您需要从实例的Settings | Users | Users菜单手动设置用户的密码。

此外,用于访问数据的方法需要用户ID,而不是用户名,因此需要使用authenticate()方法来获取用户ID。

更多

/xmlrpc/2/common端点提供了另一个方法:version()。您可以在没有凭据的情况下调用此方法。它将返回Odoo实例的版本信息。version()方法的使用示例如下:

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)

输出如下

通过XML-RPC搜索和读取数据

通过XML-RPC创建、更新、删除数据

通过XML-RPC调用函数

通过JSON-RPC登录odoo

odoo提供了JSON-RPC。正如其名,JSON-RPC使用JSOM格式,并通过jsonrpc2.0实现。本节,我们将演示如何使用JSON-RPC实现登录及获取数据。

准备

步骤

  1. 添加jsonrpc_authenticate.py文件
  2. 添加如下代码:
import json
import random
import requests

server_url = "http://localhost:8069"
db_name = "book-db-14"
username = "admin"
password = "admin"
json_endpoint = "%s/jsonrpc" % server_url
headers = {"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")
  1. 运行参数
python3 jsonrpc_authenticate.py

结果如下:

原理

JSON-RPC使用JSON格式通过/jsonrpc端点与服务器交互数据。在我们的例子中,我们使用python的requests包发起post请求,当然,你也可以通过其他的包,比如urllib。
JSON-RPC仅支持JSON-RPC 2.0格式的数据负载。你可在https://www.jsonrpc.org/specification。在我们的例子中,我们新建了get_json_payload()方法。该方法负责将数据封装成JSON-RPC 2.0格式的负载。方法接受三个参数,service、method及可变参数。JSON-RPC请求体是以JSON格式的,同时请求头需包含{"Content-Type": "application/json"}。返回结果也是JSON格式的。

与XML-RPC类似,所有公开的方法都位于common服务中。因此,我们以service=common,method=login准备负载。登录函数需要额外的参数,包括数据库名称、账户、密码。当我们的账户密码通过验证后,将得到用户的ID。

小贴士
get_json_payload()可实现代码复用。

更多

JSON-RPC同样支持version函数。我们可以获取odoo实例的版本信息。如下:

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):
	...
payload = get_json_payload('common', 'version')
response = requests.post(json_endpoint, data=payload, headers=headers)

print(response.json())

结果如下:

通过JSON-RPC获取及搜索数据

本节,我们将了解如何通过JSON-RPC获取数据。

准备

步骤

  1. 添加jsonrpc_fetch_data.py文件
  2. 添加代码
# place authentication and get_json_payload methods (see first jsonrpc recipe)
if user_id:
    # search for the book's ids
    search_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
    # read data for books ids
    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")
  1. 运行脚本
python3 jsonrpc_fetch_data.py

结果如下:

原理

在上一节中,我们通过JSON-RPC登录系统并获得用户的ID。现在我们可以通过用户的ID来获取模型数据了。我们需要使用search及read来获取数据。为了获取数据,我们调用了object作为service,execute_kw()作为method执行查询。execute_kw函数的参数如下:

  • 数据库的名称
  • 用户的ID
  • 密码
  • 模型名称
  • 方法名称
  • args,变量数组
  • kwargs,字典变量

在我们的例子中,我们调用了search方法。execute_kw()函数将强制变量作为位置变量,将可选变量作为关键字变量。在search方法中,domain是强制变量,可选变量Limit是关键字变量。
步骤2,我们调用了read方法获取图书的详细信息。并将图书id的列表及字段的列表作为参数。

小贴士
我们也可以使用execute方法。该方法并不支持关键字变量,因此如果你想传递一些可选参数,你需要传递所有的中间参数。

更多

与XML-RPC类似,我们可以使用search_read()方法代替search()及read()方法的组合。如下:

# place authentication and get_json_payload methods (see firstjsonrpc recipe)
if user_id:
    # search and read for the book's ids 
    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创建、更新、删除数据

本节,我们将学习如何通过RPC实现CRUD。

准备

步骤

  1. 添加jsonrpc_operation.py文件
  2. 添加代码
# place authentication and get_json_payload method (seelast recipe for more)
if user_id:
    # creates the books records 
    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']
    # Write in existing book record 
    book_to_write = books_ids[1]
    # We will use ids of recently created books 
    write_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)
    # Delete in existing book record 
    book_to_unlink = books_ids[2:]
    # We will use ids of recently created books 
    payload = 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")
  1. 运行
python3 jsonrpc_operation.py

结果如下:

如果操作成功,write和unlink方法返回True。这意味着,如果您的响应为True,则假定一条记录已被成功更新或删除。

原理

execute_kw()函数用于create、update和delete运算。自odoo12,create方法支持同时创建多条数据。

小贴士
当您尝试创建记录而没有为required字段提供值时,JSON-RPC和XML-RPC都会生成一个错误,因此请确保您已经将所有required字段添加到创建值中。

更多

与XML-RPC一样,您可以使用JSON-RPC中的check_access_rights方法来检查您是否有执行该操作的访问权限。这个方法需要两个参数——模型名称和操作名称。在下面的示例中,我们检查create操作的访问权限:

# place authentication and get_json_payload method (see lastrecipe for more)
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")

结果如下:

通过JSON-RPC调用函数

本节,我们将学习如何通过JSON-RPC调用模型方法。比如,我们将调用图书模型的make_available()方法改变图书的状态。

准备

步骤

  1. 添加jsonrpc_method.py文件
  2. 添加代码:
# place authentication and get_json_payload method (see last recipe for more)
if user_id:
    # Create the book in draft state
    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']
    # Change the book state by calling make_available
    # method
    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()
    # Check the book status after method call
    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")
  1. 运行文件
python3 jsonrpc_method.py

前面的命令将使用draft创建一本书,然后通过调用make_available方法更改该书的状态。之后,我们将获取图书数据来检查图书的状态,这将产生以下输出:

原理

execute_kw()能够调用模型的任何公共方法。正如我们在通过XML-RPC配方调用方法中看到的,公共方法是那些名称不以_(下划线)开头的方法。以_开头的方法是私有的,你不能从JSON-RPC调用它们。
在我们的示例中,我们创建了一个状态为draft的书籍。然后,我们再进行一次RPC调用来调用make_available方法,这将把该书的状态更改为available。最后,我们再进行一次RPC调用来检查book的状态。这将显示该书的状态已更改为available,如图20.10所示。
不返回任何内容的方法在内部默认返回None。这些方法不能从RPC中使用。因此,如果您想使用来自RPC的方法,至少要添加return True语句。

OCA的odoorpc库(超好用)

OCA提供了名为odoorpc的包。可为我们提供便捷的方式与odoo实例交互。安装odoorpc:

pip install OdooRPC

步骤

  1. 添加odoorpc_library.py文件
  2. 添加代码
import odoorpc

db_name = 'book-db-14'
user_name = 'admin'
password = 'admin'

# Prepare the connection to the server
odoo = odoorpc.ODOO('localhost', port=8069)
odoo.login(db_name, user_name, password) # login

# User information
user = odoo.env.user
print(user.name)
print(user.company_id.name)
print(user.email)

BookModel = odoo.env['library.book']
search_domain = ['|', ['name', 'ilike', 'odoo'], ['name', 'ilike', 'sql']]
books_ids = BookModel.search(search_domain, limit=5)
for book in BookModel.browser(books_ids):
	print(book.name, book.date_release)
	
# create the book and update the state
book_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)
  1. 运行文件
python3 odoorpc_library.py

结果如下:

原理

odoorpc在底层使用的jsonrpc实现与odoo的交互。

更多

odoorpc为我们做了非常完美的封装,但我们依然可以会用原生的RPC语法:

import odoorpc
db_name = 'book-db-14' 
user_name = 'admin' 
password = 'admin'
# Prepare the connection to the server
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包,如下:

生成API key

odoo14开始支持双因素认证(Two-Factor Authentication, 2FA)。2FA是用户帐户的额外安全层,用户需要输入密码和基于时间的代码。如果您已经启用了2FA,那么您将不能通过输入用户ID和密码来使用RPC。要解决这个问题,您需要为用户生成一个API密钥。本节,我们将看到如何生成API密钥。

步骤

  1. 打开用户首选项并打开帐户安全选项卡。

  2. 点击New API Key按钮:

  3. 它将打开一个弹出窗口,如下图所示。输入API密钥名和点击Generate key按钮:

  4. 这将生成API密钥,并在一个新的弹出窗口中显示它。记下API键,因为你还需要它:

一旦生成了API密钥,您就可以开始以与普通密码相同的方式为RPC使用API密钥。

原理

使用API键很简单。然而,有一些事情你需要注意。API密钥是为每个用户生成的,如果您希望为多个用户使用RPC,则需要为每个用户生成API密钥。此外,用户的API密钥将拥有与用户相同的访问权限,因此如果某人获得了密钥的访问权限,他们可以执行用户可以执行的所有操作。因此,您需要对API密钥保密。

小贴士
生成API密钥时,只显示一次。你得把这个键记下来。如果你失去了它,就没有办法再找回来了。在这种情况下,您需要删除API键并生成一个新的API键。

使用API密钥非常简单。在RPC调用期间,您只需要使用API密钥而不是用户密码。即使激活了2FA,你也可以调用RPC。

posted @ 2021-03-14 12:07  老韩头的码字生活  阅读(125)  评论(0编辑  收藏  举报