外部 API

通常情况下,Odoo通过模块进行内部扩展,但其许多功能和所有数据也可以从外部进行外部分析或与各种工具集成。 模型 API的一部分可以通过XML-RPC_轻松访问,并且可以从多种语言中访问。

重要

从PHP8开始,默认情况下可能不会安装XML-RPC扩展。请查看 手册 以获取安装步骤。

注解

Access to data via the external API is only available on Custom Odoo pricing plans. Access to the external API is not available on One App Free or Standard plans. For more information visit the Odoo pricing page or reach out to your Customer Success Manager.

连接

配置

如果您已经安装了Odoo服务器,您可以直接使用它的参数。

重要

对于Odoo在线实例(<domain>.odoo.com),用户是没有 本地 密码的(作为一个人,您是通过Odoo在线认证系统登录的,而不是通过实例本身)。要在Odoo在线实例上使用XML-RPC,您需要在要使用的用户帐户上设置密码:

  • 使用管理员账户登录您的实例。

  • 转到 设置 ‣ 用户和公司 ‣ 用户

  • 点击您想要用于 XML-RPC 访问的用户。

  • 点击 操作 并选择 更改密码

  • 设置 新密码 值,然后点击 更改密码

The server url is the instance’s domain (e.g. https://mycompany.odoo.com), the database name is the name of the instance (e.g. mycompany). The username is the configured user’s login as shown by the Change Password screen.

url = <insert server URL>
db = <insert database name>
username = 'admin'
password = <insert password for your admin user (default: admin)>

API密钥

14.0 新版功能.

Odoo 支持 api keys ,并且(根据模块或设置)可能 需要 这些密钥来执行 Web 服务操作。

使用 API 密钥的方法是简单地将您的 密码 替换为密钥。登录仍然有效。您应该像对待密码一样小心地存储 API 密钥,因为它们基本上提供了与密码相同的访问权限(尽管它们不能用于通过界面登录)。

为了向您的账户添加一个密钥,只需转到您的 首选项`(或 :guilabel:`我的个人资料):

../../_images/preferences.png

然后打开 账户安全 选项卡,并点击 新建 API 密钥

../../_images/account-security.png

输入一个描述以供键使用, 此描述应尽可能清晰和完整 :这是您唯一的方式来识别您的键并知道您是否应该删除它们或保留它们。

点击 生成密钥 ,然后复制提供的密钥。 请谨慎保存此密钥 :它相当于您的密码,就像您的密码一样,系统将无法在以后检索或显示该密钥。如果您丢失了此密钥,您将不得不创建一个新的密钥(并可能删除您丢失的密钥)。

一旦您在您的账户上配置了密钥,它们将出现在 New API Key 按钮上方,并且您将能够删除它们:

../../_images/delete-key.png

已删除的 API 密钥无法恢复或重置。您将需要生成一个新的密钥,并更新所有使用旧密钥的地方。

测试数据库

为了使探索更简单,您也可以向 https://demo.odoo.com 请求一个测试数据库:

import xmlrpc.client
info = xmlrpc.client.ServerProxy('https://demo.odoo.com/start').start()
url, db, username, password = info['host'], info['database'], info['user'], info['password']

正在登录

Odoo 要求 API 用户在查询大多数数据之前进行身份验证。

The xmlrpc/2/common endpoint provides meta-calls which don’t require authentication, such as the authentication itself or fetching version information. To verify if the connection information is correct before trying to authenticate, the simplest call is to ask for the server’s version. The authentication itself is done through the authenticate function and returns a user identifier (uid) used in authenticated calls instead of the login.

common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
common.version()

结果:

{
    "server_version": "13.0",
    "server_version_info": [13, 0, 0, "final", 0],
    "server_serie": "13.0",
    "protocol_version": 1,
}
uid = common.authenticate(db, username, password, {})

调用方法

第二个端点是 xmlrpc/2/object。它用于通过 execute_kw RPC 函数调用 odoo 模型的方法。

每次调用 execute_kw 都需要传入以下参数:

  • 要使用的数据库,一个字符串

  • 用户ID(通过 authenticate 检索),一个整数

  • 用户密码,字符串类型

  • 模型名称,字符串类型

  • 方法名称,字符串类型

  • 按位置传递的参数数组/列表

  • 一个可选的参数映射/字典,通过关键字传递

Example

For instance, to search for records in the res.partner model, we can call name_search with name passed by position and limit passed by keyword (in order to get maximum 10 results):

models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password, 'res.partner', 'name_search', ['foo'], {'limit': 10})

结果:

true

列出记录

可以通过 search() 方法列出和过滤记录。

search() 接受一个必填的 domain 过滤器(可能为空),并返回与过滤器匹配的所有记录的数据库标识符。

Example

例如,列出客户公司:

models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True]]])

结果:

[7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74]

分页

默认情况下,搜索将返回与条件匹配的所有记录的ID,这可能是一个巨大的数字。 offsetlimit 参数可用于仅检索所有匹配记录的子集。

Example

models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True]]], {'offset': 10, 'limit': 5})

结果:

[13, 20, 30, 22, 29]

计算记录数

不必检索可能庞大的记录列表并对其进行计数,可以使用 search_count() 仅检索与查询匹配的记录数。它接受与 search() 相同的 domain 过滤器,没有其他参数。

Example

models.execute_kw(db, uid, password, 'res.partner', 'search_count', [[['is_company', '=', True]]])

结果:

19

注解

如果其他用户正在使用服务器,则调用 search 然后调用 search_count (或反之亦然)可能不会产生一致的结果:存储的数据可能在调用之间发生了更改。

读取记录

记录数据可以通过 read() 方法访问,该方法接受一个id列表(由 search() 返回),并可选地接受一个字段列表以获取。默认情况下,它获取当前用户可以读取的所有字段,这往往是一个巨大的数量。

Example

ids = models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True]]], {'limit': 1})
[record] = models.execute_kw(db, uid, password, 'res.partner', 'read', [ids])
# count the number of fields fetched by default
len(record)

结果:

121

相反,只选择三个被认为有趣的字段。

models.execute_kw(db, uid, password, 'res.partner', 'read', [ids], {'fields': ['name', 'country_id', 'comment']})

结果:

[{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}]

注解

即使未请求 id 字段,它也总是会返回。

列出记录字段

fields_get() 可用于检查模型的字段并检查哪些字段似乎是感兴趣的。

因为它返回大量的元信息(也被客户端程序使用),所以在打印之前应该进行过滤,对于人类用户来说,最有趣的项目是 string (字段的标签), help (如果有帮助文本)和 type (了解期望的值或在更新记录时发送的值)。

Example

models.execute_kw(db, uid, password, 'res.partner', 'fields_get', [], {'attributes': ['string', 'help', 'type']})

结果:

{
    "ean13": {
        "type": "char",
        "help": "BarCode",
        "string": "EAN13"
    },
    "property_account_position_id": {
        "type": "many2one",
        "help": "The fiscal position will determine taxes and accounts used for the partner.",
        "string": "Fiscal Position"
    },
    "signup_valid": {
        "type": "boolean",
        "help": "",
        "string": "Signup Token is Valid"
    },
    "date_localization": {
        "type": "date",
        "help": "",
        "string": "Geo Localization Date"
    },
    "ref_company_ids": {
        "type": "one2many",
        "help": "",
        "string": "Companies that refers to partner"
    },
    "sale_order_count": {
        "type": "integer",
        "help": "",
        "string": "# of Sales Order"
    },
    "purchase_order_count": {
        "type": "integer",
        "help": "",
        "string": "# of Purchase Order"
    },

搜索和阅读

因为这是一个非常常见的任务,Odoo提供了一个 search_read() 快捷方式,正如其名称所示,它相当于 search() 后跟一个 read(),但避免了执行两个请求和保留id的操作。

它的参数与 search() 相似,但它还可以接受一个 fields 列表(就像 read() 一样,如果没有提供该列表,它将获取匹配记录的所有字段)。

Example

models.execute_kw(db, uid, password, 'res.partner', 'search_read', [[['is_company', '=', True]]], {'fields': ['name', 'country_id', 'comment'], 'limit': 5})

结果:

[
    {
        "comment": false,
        "country_id": [ 21, "Belgium" ],
        "id": 7,
        "name": "Agrolait"
    },
    {
        "comment": false,
        "country_id": [ 76, "France" ],
        "id": 18,
        "name": "Axelor"
    },
    {
        "comment": false,
        "country_id": [ 233, "United Kingdom" ],
        "id": 12,
        "name": "Bank Wealthy and sons"
    },
    {
        "comment": false,
        "country_id": [ 105, "India" ],
        "id": 14,
        "name": "Best Designers"
    },
    {
        "comment": false,
        "country_id": [ 76, "France" ],
        "id": 17,
        "name": "Camptocamp"
    }
]

创建记录

使用 create() 方法创建模型的记录。该方法创建单个记录并返回其数据库标识符。

create() 接受一个字段到值的映射,用于初始化记录。对于任何具有默认值且未通过映射参数设置的字段,将使用默认值。

Example

id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{'name': "New Partner"}])

结果:

78

警告

大多数值类型是我们所期望的(整数为 Integer,字符串为 CharText),

更新记录

可以使用 write() 来更新记录。它接受一个要更新的记录列表和一个更新字段到值的映射,类似于 create()

可以同时更新多条记录,但它们将会获得相同的字段值。无法执行“计算”更新(其中设置的值取决于记录的现有值)。

Example

models.execute_kw(db, uid, password, 'res.partner', 'write', [[id], {'name': "Newer partner"}])
# get record name after having changed it
models.execute_kw(db, uid, password, 'res.partner', 'read', [[id], ['display_name']])

结果:

[[78, "Newer partner"]]

删除记录

可以通过将其ID提供给 unlink() 来批量删除记录。

Example

models.execute_kw(db, uid, password, 'res.partner', 'unlink', [[id]])
# check if the deleted record is still in the database
models.execute_kw(db, uid, password, 'res.partner', 'search', [[['id', '=', id]]])

结果:

[]

检查和内省

以前我们使用 fields_get() 来查询一个模型,并且从一开始就使用了一个任意的模型,Odoo 将大部分模型元数据存储在几个元模型中,这些元模型允许通过 XML-RPC 在系统中查询和修改模型和字段(有一些限制)的运行时。

ir.model

通过其各种字段提供有关Odoo模型的信息。

name

模型的人类可读描述

model

系统中每个模型的名称

state

whether the model was generated in Python code (base) or by creating an ir.model record (manual)

field_id

通过 One2many 列表到模型的字段 ir.model.fields

view_ids

One2many to the View architectures defined for the model

access_ids

One2many 关联到模型上设置的 访问权限

ir.model can be used to

  • 查询系统中已安装的模型(作为对模型操作的前提条件或探索系统内容的先决条件)。

  • 获取特定模型的信息(通常是通过列出与其关联的字段)。

  • 通过远程过程调用动态创建新模型。

重要

  • 自定义模型名称必须以 x_ 开头。

  • 必须提供并设置 statemanual,否则模型将不会被加载。

  • 无法向自定义模型添加新的 方法 ,只能添加字段。

Example

一个自定义模型最初只包含所有模型都可用的“内置”字段:

models.execute_kw(db, uid, password, 'ir.model', 'create', [{
    'name': "Custom Model",
    'model': "x_custom_model",
    'state': 'manual',
}])
models.execute_kw(db, uid, password, 'x_custom_model', 'fields_get', [], {'attributes': ['string', 'help', 'type']})

结果:

{
    "create_uid": {
        "type": "many2one",
        "string": "Created by"
    },
    "create_date": {
        "type": "datetime",
        "string": "Created on"
    },
    "__last_update": {
        "type": "datetime",
        "string": "Last Modified on"
    },
    "write_uid": {
        "type": "many2one",
        "string": "Last Updated by"
    },
    "write_date": {
        "type": "datetime",
        "string": "Last Updated on"
    },
    "display_name": {
        "type": "char",
        "string": "Display Name"
    },
    "id": {
        "type": "integer",
        "string": "Id"
    }
}

ir.model.fields

提供有关Odoo模型字段的信息,并允许添加自定义字段,无需使用Python代码。

model_id

Many2one to ir.model to which the field belongs

name

字段的技术名称(在 readwrite 中使用)

field_description

字段的用户可读标签(例如 fields_get 中的 string

ttype

要创建的字段的 类型

state

whether the field was created via Python code (base) or via ir.model.fields (manual)

required, readonly, translate

在字段上启用相应的标志

groups

字段级访问控制,一个 Many2manyres.groups

selection, size, on_delete, relation, relation_field, domain

特定类型的属性和自定义,详见 字段文档 了解详情

重要

  • 与自定义模型一样,只有使用 state="manual" 创建的新字段才会作为实际字段激活在模型上。

  • 计算字段不能通过 ir.model.fields 添加,一些字段元信息(默认值,onchange)也不能设置。

Example

id = models.execute_kw(db, uid, password, 'ir.model', 'create', [{
    'name': "Custom Model",
    'model': "x_custom",
    'state': 'manual',
}])
models.execute_kw(db, uid, password, 'ir.model.fields', 'create', [{
    'model_id': id,
    'name': 'x_name',
    'ttype': 'char',
    'state': 'manual',
    'required': True,
}])
record_id = models.execute_kw(db, uid, password, 'x_custom', 'create', [{'x_name': "test record"}])
models.execute_kw(db, uid, password, 'x_custom', 'read', [[record_id]])

结果:

[
    {
        "create_uid": [1, "Administrator"],
        "x_name": "test record",
        "__last_update": "2014-11-12 16:32:13",
        "write_uid": [1, "Administrator"],
        "write_date": "2014-11-12 16:32:13",
        "create_date": "2014-11-12 16:32:13",
        "id": 1,
        "display_name": "test record"
    }
]