外部 API¶
Odoo 通常通过模块在内部进行扩展,但它的许多功能和所有数据也可以从外部访问,用于外部分析或与各种工具集成。部分 模型 API 可以通过 XML-RPC 轻松访问,并支持多种编程语言。
重要
从 PHP8 开始,XML-RPC 扩展可能默认不可用。请查看 手册 了解安装步骤。
注解
通过外部 API 访问数据仅适用于 自定义 Odoo 定价计划。外部 API 访问权限在 单应用免费版 或 标准版 计划中不可用。更多信息,请访问 Odoo 定价页面 或联系您的客户成功经理。
参见
连接¶
配置¶
如果您已经安装了 Odoo 服务器,则可以直接使用其参数。
重要
对于 Odoo 在线实例(<domain>.odoo.com),用户创建时没有 本地 密码(作为用户,您是通过 Odoo 在线身份验证系统登录,而不是由实例本身处理)。要在 Odoo 在线实例上使用 XML-RPC,您需要为要使用的用户账户设置密码:
使用管理员账户登录您的实例。
前往
。点击您希望用于 XML-RPC 访问的用户。
点击 操作 并选择 更改密码 。
设置一个新的 新密码 值,然后点击 更改密码。
服务器 URL 是实例的域名(例如 https://mycompany.odoo.com),数据库名称 是实例的名称(例如 mycompany)。用户名 是 更改密码 页面显示的配置用户的登录名。
url = <insert server URL>
db = <insert database name>
username = 'admin'
password = <insert password for your admin user (default: admin)>
url = <insert server URL>
db = <insert database name>
username = "admin"
password = <insert password for your admin user (default: admin)>
$url = <insert server URL>;
$db = <insert database name>;
$username = "admin";
$password = <insert password for your admin user (default: admin)>;
final String url = <insert server URL>,
db = <insert database name>,
username = "admin",
password = <insert password for your admin user (default: admin)>;
var (
url = <insert server URL>
db = <insert database name>
username = "admin"
password = <insert password for your admin user (default: admin)>
)
API 密钥¶
14.0 新版功能.
Odoo 支持 API 密钥,并且(根据模块或设置)可能 要求 使用这些密钥来执行 Web 服务操作。
在脚本中使用 API 密钥的方式是简单地将您的 密码 替换为密钥。登录名仍然保持不变。您应该像对待密码一样小心存储 API 密钥,因为它们本质上提供了对您用户账户的相同访问权限(尽管它们不能用于通过界面登录)。
为了向您的账户添加密钥,只需前往您的 偏好设置 (或 我的个人资料 ):

然后打开 账户安全 标签页,并点击 新建 API 密钥 :

输入密钥的描述,该描述应尽可能清晰完整:这是您日后识别密钥并判断是否应删除或保留它们的唯一方法。
点击 生成密钥 ,然后复制提供的密钥。请妥善保存此密钥:它等同于您的密码,就像您的密码一样,系统以后无法检索或再次显示该密钥。如果您丢失了此密钥,则需要创建一个新的密钥(并可能删除丢失的那个)。
一旦您在账户中配置了密钥,它们将出现在 新建 API 密钥 按钮上方,并且您可以删除它们:

已删除的 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']
require "xmlrpc/client"
info = XMLRPC::Client.new2('https://demo.odoo.com/start').call('start')
url, db, username, password = info['host'], info['database'], info['user'], info['password']
require_once('ripcord.php');
$info = ripcord::client('https://demo.odoo.com/start')->start();
list($url, $db, $username, $password) = array($info['host'], $info['database'], $info['user'], $info['password']);
注解
这些示例使用了 Ripcord 库,该库提供了一个简单的 XML-RPC API。Ripcord 要求在您的 PHP 安装中启用 XML-RPC 支持。
由于调用是通过 HTTPS 执行的,因此还需要启用 OpenSSL 扩展。
final XmlRpcClient client = new XmlRpcClient();
final XmlRpcClientConfigImpl start_config = new XmlRpcClientConfigImpl();
start_config.setServerURL(new URL("https://demo.odoo.com/start"));
final Map<String, String> info = (Map<String, String>)client.execute(
start_config, "start", emptyList());
final String url = info.get("host"),
db = info.get("database"),
username = info.get("user"),
password = info.get("password");
client, err := xmlrpc.NewClient("https://demo.odoo.com/start", nil)
if err != nil {
log.Fatal(err)
}
info := map[string]string{}
client.Call("start", nil, &info)
url = info["host"].(string)
db = info["database"].(string)
username = info["user"].(string)
password = info["password"].(string)
登录¶
Odoo 要求 API 用户在查询大多数数据之前进行身份验证。
xmlrpc/2/common
端点提供了一些不需要身份验证的元调用,例如身份验证本身或获取版本信息。在尝试进行身份验证之前,为了验证连接信息是否正确,最简单的调用是请求服务器版本。身份验证本身通过 authenticate
函数完成,并返回一个用户标识符( uid
),该标识符用于代替登录名进行身份验证调用。
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
common.version()
common = XMLRPC::Client.new2("#{url}/xmlrpc/2/common")
common.call('version')
$common = ripcord::client("$url/xmlrpc/2/common");
$common->version();
final XmlRpcClientConfigImpl common_config = new XmlRpcClientConfigImpl();
common_config.setServerURL(new URL(String.format("%s/xmlrpc/2/common", url)));
client.execute(common_config, "version", emptyList());
client, err := xmlrpc.NewClient(fmt.Sprintf("%s/xmlrpc/2/common", url), nil)
if err != nil {
log.Fatal(err)
}
common := map[string]any{}
if err := client.Call("version", nil, &common); err != nil {
log.Fatal(err)
}
结果:
{
"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, {})
uid = common.call('authenticate', db, username, password, {})
$uid = $common->authenticate($db, $username, $password, array());
int uid = (int)client.execute(common_config, "authenticate", asList(db, username, password, emptyMap()));
var uid int64
if err := client.Call("authenticate", []any{
db, username, password,
map[string]any{},
}, &uid); err != nil {
log.Fatal(err)
}
调用方法¶
第二个端点是 xmlrpc/2/object
。它通过 execute_kw
RPC 函数调用 Odoo 模型的方法。
每次调用 execute_kw
时需要以下参数:
使用的数据库,字符串类型
用户 ID(通过
authenticate
获取),整数类型用户的密码,字符串类型
模型名称,字符串类型
方法名称,字符串类型
按位置传递的参数数组/列表
按关键字传递的参数映射/字典(可选)
Example
例如,要在 res.partner
模型中搜索记录,我们可以调用 name_search
,按位置传递 name
并按关键字传递 limit
(以获取最多 10 个结果):
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password, 'res.partner', 'name_search', ['foo'], {'limit': 10})
models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy
models.execute_kw(db, uid, password, 'res.partner', 'name_search', ['foo'], {limit: 10})
$models = ripcord::client("$url/xmlrpc/2/object");
$models->execute_kw($db, $uid, $password, 'res.partner', 'name_search', array('foo'), array('limit' => 10));
final XmlRpcClient models = new XmlRpcClient() {{
setConfig(new XmlRpcClientConfigImpl() {{
setServerURL(new URL(String.format("%s/xmlrpc/2/object", url)));
}});
}};
models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "name_search",
asList("foo"),
new HashMap() {{ put("limit", 10); }}
));
models, err := xmlrpc.NewClient(fmt.Sprintf("%s/xmlrpc/2/object", url), nil)
if err != nil {
log.Fatal(err)
}
var result bool
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "name_search",
[]string{"foo"},
map[string]bool{"limit": 10},
}, &result); err != nil {
log.Fatal(err)
}
结果:
true
列出记录¶
可以通过 search()
列出和过滤记录。
search()
接受一个强制的 域 过滤器(可能为空),并返回所有匹配过滤器的记录的数据库标识符。
Example
例如,列出客户公司:
models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True]]])
models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', true]]])
$models->execute_kw($db, $uid, $password, 'res.partner', 'search', array(array(array('is_company', '=', true))));
asList((Object[])models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "search",
asList(asList(
asList("is_company", "=", true)))
)));
var records []int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "search",
[]any{[]any{
[]any{"is_company", "=", true},
}},
}, &records); err != nil {
log.Fatal(err)
}
结果:
[7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74]
分页¶
默认情况下,搜索将返回所有符合条件的记录 ID,这可能会是一个巨大的数字。可以使用 offset
和 limit
参数来仅检索所有匹配记录的一个子集。
Example
models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True]]], {'offset': 10, 'limit': 5})
models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', true]]], {offset: 10, limit: 5})
$models->execute_kw($db, $uid, $password, 'res.partner', 'search', array(array(array('is_company', '=', true))), array('offset'=>10, 'limit'=>5));
asList((Object[])models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "search",
asList(asList(
asList("is_company", "=", true))),
new HashMap() {{ put("offset", 10); put("limit", 5); }}
)));
var records []int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "search",
[]any{[]any{
[]any{"is_company", "=", true},
}},
map[string]int64{"offset": 10, "limit": 5},
}, &records); err != nil {
log.Fatal(err)
}
结果:
[13, 20, 30, 22, 29]
计数记录¶
与其检索可能庞大的记录列表并对其进行计数,不如使用 search_count()
来仅检索与查询匹配的记录数量。它接受与 search()
相同的 域 过滤器,并且没有其他参数。
Example
models.execute_kw(db, uid, password, 'res.partner', 'search_count', [[['is_company', '=', True]]])
models.execute_kw(db, uid, password, 'res.partner', 'search_count', [[['is_company', '=', true]]])
$models->execute_kw($db, $uid, $password, 'res.partner', 'search_count', array(array(array('is_company', '=', true))));
(Integer)models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "search_count",
asList(asList(
asList("is_company", "=", true)))
));
var counter int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "search_count",
[]any{[]any{
[]any{"is_company", "=", true},
}},
}, &counter); err != nil {
log.Fatal(err)
}
结果:
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)
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]).first
# count the number of fields fetched by default
record.length
$ids = $models->execute_kw($db, $uid, $password, 'res.partner', 'search', array(array(array('is_company', '=', true))), array('limit'=>1));
$records = $models->execute_kw($db, $uid, $password, 'res.partner', 'read', array($ids));
// count the number of fields fetched by default
count($records[0]);
final List ids = asList((Object[])models.execute(
"execute_kw", asList(
db, uid, password,
"res.partner", "search",
asList(asList(
asList("is_company", "=", true))),
new HashMap() {{ put("limit", 1); }})));
final Map record = (Map)((Object[])models.execute(
"execute_kw", asList(
db, uid, password,
"res.partner", "read",
asList(ids)
)
))[0];
// count the number of fields fetched by default
record.size();
var ids []int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "search",
[]any{[]any{
[]any{"is_company", "=", true},
}},
map[string]int64{"limit": 1},
}, &ids); err != nil {
log.Fatal(err)
}
var records []any
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "read",
ids,
}, &records); err != nil {
log.Fatal(err)
}
// count the number of fields fetched by default
count := len(records)
结果:
121
相反,仅选择三个被认为有趣的字段。
models.execute_kw(db, uid, password, 'res.partner', 'read', [ids], {'fields': ['name', 'country_id', 'comment']})
models.execute_kw(db, uid, password, 'res.partner', 'read', [ids], {fields: %w(name country_id comment)})
$models->execute_kw($db, $uid, $password, 'res.partner', 'read', array($ids), array('fields'=>array('name', 'country_id', 'comment')));
asList((Object[])models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "read",
asList(ids),
new HashMap() {{
put("fields", asList("name", "country_id", "comment"));
}}
)));
var recordFields []map[string]any
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "read",
ids,
map[string][]string{
"fields": {"name", "country_id", "comment"},
},
}, &recordFields); err != nil {
log.Fatal(err)
}
结果:
[{"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']})
models.execute_kw(db, uid, password, 'res.partner', 'fields_get', [], {attributes: %w(string help type)})
$models->execute_kw($db, $uid, $password, 'res.partner', 'fields_get', array(), array('attributes' => array('string', 'help', 'type')));
(Map<String, Map<String, Object>>)models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "fields_get",
emptyList(),
new HashMap() {{
put("attributes", asList("string", "help", "type"));
}}
));
recordFields := map[string]string{}
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "fields_get",
[]any{},
map[string][]string{
"attributes": {"string", "help", "type"},
},
}, &recordFields); err != nil {
log.Fatal(err)
}
结果:
{
"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})
models.execute_kw(db, uid, password, 'res.partner', 'search_read', [[['is_company', '=', true]]], {fields: %w(name country_id comment), limit: 5})
$models->execute_kw($db, $uid, $password, 'res.partner', 'search_read', array(array(array('is_company', '=', true))), array('fields'=>array('name', 'country_id', 'comment'), 'limit'=>5));
asList((Object[])models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "search_read",
asList(asList(
asList("is_company", "=", true))),
new HashMap() {{
put("fields", asList("name", "country_id", "comment"));
put("limit", 5);
}}
)));
var recordFields []map[string]any
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "search_read",
[]any{[]any{
[]any{"is_company", "=", true},
}},
map[string]any{
"fields": []string{"name", "country_id", "comment"},
"limit": 5,
},
}, &recordFields); err != nil {
log.Fatal(err)
}
结果:
[
{
"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"}])
id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{name: "New Partner"}])
$id = $models->execute_kw($db, $uid, $password, 'res.partner', 'create', array(array('name'=>"New Partner")));
final Integer id = (Integer)models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "create",
asList(new HashMap() {{ put("name", "New Partner"); }})
));
var id int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "create",
[]map[string]string{
{"name": "New Partner"},
},
}, &id); err != nil {
log.Fatal(err)
}
结果:
78
更新记录¶
可以使用 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']])
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']])
$models->execute_kw($db, $uid, $password, 'res.partner', 'write', array(array($id), array('name'=>"Newer partner")));
// get record name after having changed it
$models->execute_kw($db, $uid, $password,
'res.partner', 'read', array(array($id), array('display_name')));
models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "write",
asList(
asList(id),
new HashMap() {{ put("name", "Newer Partner"); }}
)
));
// get record name after having changed it
asList((Object[])models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "read",
asList(asList(id), asList("display_name"))
)));
var result bool
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "write",
[]any{
[]int64{id},
map[string]string{"name": "Newer partner"},
},
}, &result); err != nil {
log.Fatal(err)
}
// get record name after having changed it
var record []any
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "name_get",
[]any{
[]int64{id},
},
}, &record); err != nil {
log.Fatal(err)
}
结果:
[[78, "Newer partner"]]
删除记录¶
可以通过向 unlink()
提供记录 ID 来批量删除记录。
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]]])
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]]])
$models->execute_kw($db, $uid, $password, 'res.partner', 'unlink', array(array($id)));
// check if the deleted record is still in the database
$models->execute_kw(
$db, $uid, $password, 'res.partner', 'search', array(array(array('id', '=', $id)))
);
models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "unlink",
asList(asList(id))));
// check if the deleted record is still in the database
asList((Object[])models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "search",
asList(asList(asList("id", "=", 78)))
)));
var result bool
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "unlink",
[]any{
[]int64{id},
},
}, &result); err != nil {
log.Fatal(err)
}
// check if the deleted record is still in the database
var record []any
if err := models.Call("execute_kw", []any{
db, uid, password,
"res.partner", "search",
[]any{[]any{
[]any{"id", "=", id},
}},
}, &record); err != nil {
log.Fatal(err)
}
结果:
[]
检查与自省¶
虽然我们之前使用 fields_get()
查询模型,并从一开始就在使用任意模型,但 Odoo 将大部分模型元数据存储在几个元模型中,这些元模型允许通过 XML-RPC 查询系统并在运行时动态修改模型和字段(有一些限制)。
ir.model
¶
通过其各种字段提供有关 Odoo 模型的信息。
name
模型的人类可读描述
model
系统中每个模型的名称
state
模型是通过 Python 代码生成的(
base
)还是通过创建ir.model
记录生成的(manual
)field_id
通过
One2many
到 ir.model.fields 的模型字段列表view_ids
access_ids
ir.model
可用于
查询系统中已安装的模型(作为对模型进行操作或探索系统内容的前提条件)。
获取有关特定模型的信息(通常是通过列出与其关联的字段)。
通过 RPC 动态创建新模型。
重要
自定义模型名称必须以
x_
开头。必须提供
state
并将其设置为manual
,否则模型将不会被加载。无法向自定义模型添加新的 方法,只能添加字段。
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']})
$models->execute_kw($db, $uid, $password, 'ir.model', 'create', array(array(
'name' => "Custom Model",
'model' => 'x_custom_model',
'state' => 'manual'
)));
$models->execute_kw($db, $uid, $password, 'x_custom_model', 'fields_get', array(), array('attributes' => array('string', 'help', 'type')));
models.execute_kw(db, uid, password, 'ir.model', 'create', [{
name: "Custom Model",
model: 'x_custom_model',
state: 'manual'
}])
fields = models.execute_kw(db, uid, password, 'x_custom_model', 'fields_get', [], {attributes: %w(string help type)})
models.execute(
"execute_kw", asList(
db, uid, password,
"ir.model", "create",
asList(new HashMap<String, Object>() {{
put("name", "Custom Model");
put("model", "x_custom_model");
put("state", "manual");
}})
));
final Object fields = models.execute(
"execute_kw", asList(
db, uid, password,
"x_custom_model", "fields_get",
emptyList(),
new HashMap<String, Object> () {{
put("attributes", asList(
"string",
"help",
"type"));
}}
));
var id int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"ir.model", "create",
[]map[string]string{
{
"name": "Custom Model",
"model": "x_custom_model",
"state": "manual",
},
},
}, &id); err != nil {
log.Fatal(err)
}
recordFields := map[string]string{}
if err := models.Call("execute_kw", []any{
db, uid, password,
"x_custom_model", "fields_get",
[]any{},
map[string][]string{
"attributes": {"string", "help", "type"},
},
}, &recordFields); err != nil {
log.Fatal(err)
}
结果:
{
"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
name
字段的技术名称(用于
read
或write
)field_description
字段的用户可读标签(例如
fields_get
中的string
)ttype
要创建的字段的 类型
state
字段是通过 Python 代码创建的(
base
)还是通过ir.model.fields
创建的(manual
)required
、readonly
、translate
启用字段上的相应标志
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]])
$id = $models->execute_kw($db, $uid, $password, 'ir.model', 'create', array(array(
'name' => "Custom Model",
'model' => 'x_custom',
'state' => 'manual'
)));
$models->execute_kw($db, $uid, $password, 'ir.model.fields', 'create', array(array(
'model_id' => $id,
'name' => 'x_name',
'ttype' => 'char',
'state' => 'manual',
'required' => true
)));
$record_id = $models->execute_kw($db, $uid, $password, 'x_custom', 'create', array(array('x_name' => "test record")));
$models->execute_kw($db, $uid, $password, 'x_custom', 'read', array(array($record_id)));
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]])
final Integer id = (Integer)models.execute(
"execute_kw", asList(
db, uid, password,
"ir.model", "create",
asList(new HashMap<String, Object>() {{
put("name", "Custom Model");
put("model", "x_custom");
put("state", "manual");
}})
));
models.execute(
"execute_kw", asList(
db, uid, password,
"ir.model.fields", "create",
asList(new HashMap<String, Object>() {{
put("model_id", id);
put("name", "x_name");
put("ttype", "char");
put("state", "manual");
put("required", true);
}})
));
final Integer record_id = (Integer)models.execute(
"execute_kw", asList(
db, uid, password,
"x_custom", "create",
asList(new HashMap<String, Object>() {{
put("x_name", "test record");
}})
));
client.execute(
"execute_kw", asList(
db, uid, password,
"x_custom", "read",
asList(asList(record_id))
));
var id int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"ir.model", "create",
[]map[string]string{
{
"name": "Custom Model",
"model": "x_custom",
"state": "manual",
},
},
}, &id); err != nil {
log.Fatal(err)
}
var fieldId int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"ir.model.fields", "create",
[]map[string]any{
{
"model_id": id,
"name": "x_name",
"ttype": "char",
"state": "manual",
"required": true,
},
},
}, &fieldId); err != nil {
log.Fatal(err)
}
var recordId int64
if err := models.Call("execute_kw", []any{
db, uid, password,
"x_custom", "create",
[]map[string]string{
{"x_name": "test record"},
},
}, &recordId); err != nil {
log.Fatal(err)
}
var recordFields []map[string]any
if err := models.Call("execute_kw", []any{
db, uid, password,
"x_custom", "read",
[][]int64{{recordId}},
}, recordFields); err != nil {
log.Fatal(err)
}
结果:
[
{
"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"
}
]