Стандартным механизмом для расширения функционала Odoo является использование модулей, но многие его функции и все данные доступны извне для анализа или интеграции с различными инструментами. Часть API Model Reference доступна через XML-RPC и может быть задействована на разных языках программирования.
Соединение
import xmlrpclib
info = xmlrpclib.ServerProxy('https://demo.odoo.com/start').start()
url, db, username, password = \
info['host'], info['database'], info['user'], info['password']
common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
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']
common = XMLRPC::Client.new2("#{url}/xmlrpc/2/common")
uid = common.call('authenticate', db, username, password, {})
models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy
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");
final XmlRpcClientConfigImpl common_config = new XmlRpcClientConfigImpl();
common_config.setServerURL(new URL(String.format("%s/xmlrpc/2/common", url)));
int uid = (int)client.execute(
common_config, "authenticate", Arrays.asList(
db, username, password, emptyMap()));
final XmlRpcClient models = new XmlRpcClient() {{
setConfig(new XmlRpcClientConfigImpl() {{
setServerURL(new URL(String.format("%s/xmlrpc/2/object", url)));
}});
}};
Настройка
Если у вас уже есть установленные сервер Odoo, то вы может использовать следующие параметры
Предупреждение
Для экземпляров Odoo Online (<домен> .odoo.com) пользователи создаются без локального пароля (вы авторизуетесь как пользователь, вошедший в систему через систему аутентификации Odoo Online, а не на самом сервере). Чтобы использовать XML-RPC на экземплярах Odoo Online, вам необходимо установить пароль для учетной записи пользователя, которую вы хотите использовать:
- Зайдите как администратор
- Перейдите
- Кликните на пользователя, которому хотите предоставить доступ с помощью XML-RPC
- Кликните по кнопке Изменить пароль
- Введите в поле Новый пароль собственно сам пароль а затем нажмине Изменить пароль.
Параметр url будет таким же как ссылка к вашему экземпляру Odoo Online (например https://mycompany.odoo.com), параметр database name это имя экземпляра (например mycompany). Парметр username это логин пользователя, для которого вы меняли пароль.
- Python
- Ruby
- PHP
- Java
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)>;
Демо
Чтобы упростить себе жизнь, вы также можете запросить тестовую базу данных по этой ссылке https://demo.odoo.com:
- Python
- Ruby
- PHP
- Java
import xmlrpclib
info = xmlrpclib.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']);
Примечание
These examples use the Ripcord library, which provides a simple XML-RPC API. Ripcord requires that XML-RPC support be enabled in your PHP installation.
Since calls are performed over HTTPS, it also requires that the OpenSSL extension be enabled.
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");
Авторизация
Odoo требует чтобы пользователи API проходили авторизацию прежде чем они смогут делать запросы.
Эндпоинт xmlrpc/2/common предоставляет доступ к вызовам, которые не требуют аутентификации, например сама аутентификация или запрос информации о версии. Самый простой способ проверить правильность информации о соединении перед аутентификацией - запросить версию сервера. Сама аутентификация выполняется через функцию``authenticate`` и возвращает идентификатор пользователя (uid) используемый в дальнейшем вместо логина.
- Python
- Ruby
- PHP
- Java
common = xmlrpclib.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());
{
"server_version": "8.0",
"server_version_info": [8, 0, 0, "final", 0],
"server_serie": "8.0",
"protocol_version": 1,
}
- Python
- Ruby
- PHP
- Java
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()));
Методы
Вторым эндпоинтом является xmlrpc/2/object, он используется для вызова методов моделей с помощью функции удаленного вызова процедур(RPC) execute_kw .
Каждый вызов execute_kw принимает следующие параметры:
- имя базы данных - string
- идентификатор пользователя (полученный с помощью функции
authenticate) - integer - пароль пользователя - строка
- имя модели - строка
- имя вызываемого метода внутри модели - строка
- список позиционных параметров - массив/список
- ключевые параметры - словарь
Например, если мы имеет доступ для чтения к модели res.partner мы можем вызвать метод check_access_rights с позиционным аргументом operation и ключевым аргуметом raise_exception (чтобы получить результат true/false , а не true/error):
- Python
- Ruby
- PHP
- Java
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password,
'res.partner', 'check_access_rights',
['read'], {'raise_exception': False})
models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy
models.execute_kw(db, uid, password,
'res.partner', 'check_access_rights',
['read'], {raise_exception: false})
$models = ripcord::client("$url/xmlrpc/2/object");
$models->execute_kw($db, $uid, $password,
'res.partner', 'check_access_rights',
array('read'), array('raise_exception' => false));
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", "check_access_rights",
asList("read"),
new HashMap() {{ put("raise_exception", false); }}
));
true
Список записей
Записи могут быть перечислены и отфильтрованы с помощью search().
search() принимает обязательный параметр:ref:[UNKNOWN NODE title_reference] (возможно пустой) и возвращает id базы данных всех записей, соответствующих фильтру. Например перечислить клиентов, который являются компаниями,:
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', True], ['customer', '=', True]]])
models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', true], ['customer', '=', true]]])
$models->execute_kw($db, $uid, $password,
'res.partner', 'search', array(
array(array('is_company', '=', true),
array('customer', '=', true))));
asList((Object[])models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "search",
asList(asList(
asList("is_company", "=", true),
asList("customer", "=", true)))
)));
[7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74]
Разбиение на страницы
По умолчанию поиск вернет идентификаторы всех записей, соответствующих условию, которое может быть очень велико. Параметры offset и limit позволяют возвращать подмножества всех записей, удовлетворяющих запросу.
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', True], ['customer', '=', True]]],
{'offset': 10, 'limit': 5})
models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', true], ['customer', '=', true]]],
{offset: 10, limit: 5})
$models->execute_kw($db, $uid, $password,
'res.partner', 'search',
array(array(array('is_company', '=', true),
array('customer', '=', 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),
asList("customer", "=", true))),
new HashMap() {{ put("offset", 10); put("limit", 5); }}
)));
[13, 20, 30, 22, 29]
Количество записей
Вместо того, чтобы запросить гигантский список записей, а затем посчитать их, search_count() запрос может быть использован для получения только количества записей удовлетворяющих условию. Он использует такой же domain фильтр, как и search() и никаких других параметров.
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'search_count',
[[['is_company', '=', True], ['customer', '=', True]]])
models.execute_kw(db, uid, password,
'res.partner', 'search_count',
[[['is_company', '=', true], ['customer', '=', true]]])
$models->execute_kw($db, $uid, $password,
'res.partner', 'search_count',
array(array(array('is_company', '=', true),
array('customer', '=', true))));
(Integer)models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "search_count",
asList(asList(
asList("is_company", "=", true),
asList("customer", "=", true)))
));
19
Предупреждение
Запрос search, а затем search_count (или в обратном порядке) может не выдать согласованного результата, если другие пользователи используют сервер: сохраненные данные могли быть изменены между запросами
Чтение записей
Доступ к данным записи осуществляется с помощью метода read(), который содержит список идентификаторов (которые были возвращены по запросу: search()) и опционально список полей, данные из которых мы хотим получить. По умолчанию вы получите значение всех полей, к которым имеет доступ текущий пользователь, количество которых может быть очень большим.
- Python
- Ruby
- PHP
- Java
ids = models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', True], ['customer', '=', 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], ['customer', '=', 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('customer', '=', 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),
asList("customer", "=", 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();
121
В случае, если нам интересны только три поля.
- Python
- Ruby
- PHP
- Java
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"));
}}
)));
[{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}]
Примечание
Даже если id поля не был запрошен, его значение всегда будет содержаться в ответе
Список полей записи
fields_get() может быть использован для для проверки полей модели на наличие интересующей вас информации.
Поскольку данный запрос возвращает большое количество мета-информации (он так же используется программами-клиентами), она должна быть отфильтрована перед печатью, наиболее интересные элементы для человеческого восприятия это string (описание поля), help (справочный текст, если имеется) и type (чтобы знать какое значение ожидать или посылать при обновлении записи):
- Python
- Ruby
- PHP
- Java
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"));
}}
));
{
"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(), но вместо двух запросов позволяет сделать один и сохранить идентификаторы.
Его аргументы такие же как и у search()“s, но он так же понимает список fields (как read(), если в этом списке нет критериев выбора, он вернет все поля совпадающих с условиями поиска записей):
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'search_read',
[[['is_company', '=', True], ['customer', '=', True]]],
{'fields': ['name', 'country_id', 'comment'], 'limit': 5})
models.execute_kw(db, uid, password,
'res.partner', 'search_read',
[[['is_company', '=', true], ['customer', '=', 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('customer', '=', 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),
asList("customer", "=", true))),
new HashMap() {{
put("fields", asList("name", "country_id", "comment"));
put("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(). Метод создаст одну запись и вернет ее id.
create() принимает словарь где ключ это имя поля, а значение - сохраняемые туда данные использует их для инициализации записи. Для каждого поля, для которого не указаны пара имя-значение, будет присвоено значение по умолчанию.
- Python
- Ruby
- PHP
- Java
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"); }})
));
78
Предупреждение
в то время как большинство значений типов называются так же как и сами типы (integer для Integer, string для Char или Text),
Date,DatetimeиBinaryиспользуют строковые значенияOne2manyиMany2manyиспользуют специальную команду протокола, которая описана вдокументации по методу write.
Обновление записей
Значение записей могут быть обновлены используя метод write(), он принимает список записей и словарь обновлямых полей и их значений точно так же как и метод create().
Несколько записей могут обновляться одновременно, но все они получат одинаковые значения для всех указанных полей. В настоящее время невозможно выполнить «вычисляемые» обновления (когда устанавливаемое значение зависит от существующего значения записи).
- Python
- Ruby
- PHP
- Java
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', 'name_get', [[id]])
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', 'name_get', [[id]])
$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', 'name_get', array(array($id)));
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", "name_get",
asList(asList(id))
)));
[[78, "Newer partner"]]
Удаление записей
Записи могут быть удалены массово, путем указания их id unlink().
- Python
- Ruby
- PHP
- Java
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)))
)));
[]
Контроль и самоанализ
Ранее мы использовали fields_get() для запроса модели и с самого начала использовали произвольную модель данных, Odoo хранит большинство метаданных модели внутри нескольких мета моделей, что позволяет, как делать запросы к системе так и изменять модели данных и поля (с некоторыми ограничениями) на лету через XML-RPC.
ir.model
Предоставляет информацию о моделях Odoo через различные поля
name- понятное человеку описание модели
model- имя каждой модели в системе
state- Была ли модель сгенерирована в коде Python (
base) или же создана запись вir.model(manual) field_id- Список полей модели связанных через
One2manyс ir.model.fields view_idsOne2manyв Представления, определенные для моделиaccess_idsOne2manyссылается на Контроль доступа, установленного для модели
ir.model можно использовать для
- опрашивать систему об установленных моделях (в качестве предварительного условия для работы с моделью или для изучения содержимого системы)
- получить информацию о конкретной модели (как правило, путем перечисления полей, связанных с ней)
- динамически создавать новые модели с помощью удаленного вызова процедур (RPC)
Предупреждение
- «произвольное» имя модели данных должно начинаться с
x_ - поле
stateдолжно иметь значениеmanual, в противном случае модель данных не загрузится - Невозможно добавлять новые методы в пользовательскую модель, только поля
Пользовательская модель данных первоначально будет содержать только «встроенные» поля, доступные для всех моделей:
- Python
- PHP
- Ruby
- Java
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"));
}}
));
{
"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_idMany2oneссылается на ir.model, к которому принадлежит полеname- техническое имя поля (используется в работе методов``read`` или
write) field_description- понятное для человека описание поля (например
stringвfields_get) ttype- type (тип) создаваемого поля
state- было ли поле создано с помощью кода Python (
base) или черезir.model.fields(manual) required,readonly,translate- Включает соответствующий флаг на поле
groups- field-level access control, a
Many2manyкres.groups selection,size,on_delete,relation,relation_field,domain- типозависимые свойства и настройки, смотрите детальное описание полей для более подробного понимания
Как и в пользовательских моделях , в качестве фактических полей модели активируются только новые поля, созданные с помощью state="manual".
Предупреждение
Вычисленные поля не могут быть добавлены через ir.model.fields, некоторая мета-информация поля (defaults, onchange)) не может быть установлена
- Python
- PHP
- Ruby
- Java
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))
));
[
{
"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"
}
]