JSON-RPC
JSON, short for JavaScript Object Notation, is a widely used data format in apps and APIs. Its key advantage lies in its ease of writing, parsing, reading, and interpretation.
For Python method calls from a distance, RPC (Remote Procedure Call) is an option. JSON-RPC, a lightweight protocol, facilitates these remote procedure calls without maintaining a state. This specification outlines data structures and their processing rules. It's versatile, working across processes, sockets, HTTP, and various message passing systems.
The json-rpc API method in Odoo enables remote connections to the Odoo server. This RPC utilizes JSON encoding and is similar to XML-RPC but significantly lighter. Unlike XML-RPC, it doesn't require a response to transmit data to the server.
Connection to Odoo
Let's analyze how to connect to Odoo using the json-rpc method.
import json
import json
import random
import urllib.request
host = 'localhost'
port = 8017
database = 'Demo'
user = 'admin'
password = 'admin'
def json_rpc(url, method, params):
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": random.randint(0, 1000000000),
}
req = urllib.request.Request(url=url, data=json.dumps(data).encode(), headers={
"Content-Type":"application/json",
})
reply = json.loads(urllib.request.urlopen(req).read().decode('UTF-8'))
if reply.get("error"):
raise Exception(reply["error"])
return reply["result"]
def call(url, service, method, *args):
return json_rpc(url, "call", {"service": service, "method": method, "args": args})
url = "http://%s:%s/jsonrpc" % (host, port)
uid = call(url, "common", "login", database, user, password)
print(uid)
(Py3.6_venv) cybrosys@cybrosys:~/json-rpc$ python3 json-test.py
This will give output as the ID of the user.
url: Specifying the URL of JSON-RPC with host and port number
service: Set the service as common
method: Set the method as login
args: Pass the argument as given below:
database: name of database
user: login user id
password: password of user
Search/ Read Records
We can use JSON RPC to get and handle data in a database. This method makes it easy to fetch, search, and read data from the database smoothly.
import json
import random
import urllib.request
host = 'localhost'
port = 8017
database = 'Demo'
user = 'admin'
password = 'admin'
def json_rpc(url, method, params):
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": random.randint(0, 1000000000),
}
req = urllib.request.Request(url=url, data=json.dumps(data).encode(), headers={
"Content-Type":"application/json",
})
reply = json.loads(urllib.request.urlopen(req).read().decode('UTF-8'))
if reply.get("error"):
raise Exception(reply["error"])
return reply["result"]
def call(url, service, method, *args):
return json_rpc(url, "call", {"service": service, "method": method, "args": args})
url = "http://%s:%s/jsonrpc" % (host, port)
uid = call(url, "common", "login", database, user, password)
task_ids = call(url, "object", "execute", database, uid, password, "project.task", "read", [1])
print("Tasks: ", task_ids)
Specify the JSON-RPC URL by providing the host and port number.
Define the service as an object.
Set the method to "execute."
Pass the following arguments:
- "database": the name of the database
- "uid": the user ID
- "password": the user's password
- "model_name": the name of the model
- "method": set it to "read" to invoke the read method
- "ids": a list of IDs for which data should be read
The output will be:
python3 json-test.py
Tasks: [{'id': 1, 'rating_ids': [], 'rating_last_value': 0.0, 'rating_last_feedback': False, 'rating_last_image': False, 'rating_count': 0,
'rating_avg': 0.0, 'rating_avg_text': 'none', 'rating_percentage_satisfaction': -1.0, 'rating_last_text': False, 'activity_ids': [],
'activity_state': False, 'activity_user_id': False, 'activity_type_id': False, 'activity_type_icon': False, 'activity_date_deadline': False, 'my_activity_date_deadline': False,
'activity_summary': False, 'activity_exception_decoration': False, 'activity_exception_icon': False, 'message_is_follower': True, 'message_follower_ids': [29, 30, 31], 'message_partner_ids': [3, 7], 'message_ids': [45], 'has_message': True, 'message_needaction': False, 'message_needaction_counter': 0, 'message_has_error': False, 'message_has_error_counter': 0,
'message_attachment_count': 0, 'message_main_attachment_id': False, 'website_message_ids': [], 'message_has_sms_error': False, 'email_cc': False, 'access_url': '/my/tasks/1', 'access_token': '4c36bc36-f60a-4da8-9aa3-c81e05a7079a', 'access_warning': '', 'active': True, 'name': 'Office planning', 'description': False, 'priority': '0', 'sequence': 20, 'stage_id': [3, 'Done'], 'tag_ids': [], 'kanban_state': 'normal',
'kanban_state_label': 'In Progress', 'create_date': '2022-06-05 07:29:59', 'write_date': '2022-11-05 07:29:55', 'date_end': '2022-11-05 07:29:59', 'date_assign': False, 'date_deadline': False,
'date_last_stage_update': '2022-11-05 07:29:59', 'project_id': [1, 'Office Design'], 'task_properties': [], 'display_project_id': [1, 'Office Design'], 'planned_hours': 20.0, 'subtask_planned_hours': 0.0, 'user_ids': [], 'portal_user_names': '', 'personal_stage_type_ids': [], 'personal_stage_id': False, 'personal_stage_type_id': False,
'partner_id': [8, 'YourCompany, Joel Willis'], 'partner_is_company': False,
'commercial_partner_id': [8, 'YourCompany, Joel Willis'], 'partner_email': 'joel.willis63@example.com',
'partner_phone': '(683)-556-5104', 'partner_city': 'Bayonne', 'manager_id': [6, 'Marc Demo'], 'company_id': [1, 'YourCompany'], 'color': 7,
'project_color': 3, 'rating_active': False, 'attachment_ids': [], 'displayed_image_id': False, 'legend_blocked': 'Blocked', 'legend_done': 'Ready', 'legend_normal': 'In Progress', 'is_closed': True, 'parent_id': False, 'ancestor_id': False, 'child_ids': [], 'child_text': False, 'allow_subtasks': False, 'subtask_count': 0,
'email_from': 'joel.willis63@example.com', 'project_privacy_visibility': 'portal', 'working_hours_open': 0.0,
'working_hours_close': 880.0, 'working_days_open': 0.0, 'working_days_close': 110.0, 'is_private': False,
'allow_milestones': True, 'milestone_id': [1, 'First Phase'], 'has_late_and_unreached_milestone': False,
'allow_task_dependencies': False, 'depend_on_ids': [], 'dependent_ids': [], 'dependent_tasks_count': 0, 'is_blocked': False, 'display_parent_task_button': False,
'allow_recurring_tasks': False, 'recurring_task': False, 'recurring_count': 0, 'recurrence_id': False, 'recurrence_update': 'this', 'recurrence_message': False, 'repeat_interval': 0, 'repeat_unit': False, 'repeat_type': False,
'repeat_until': False, 'repeat_number': 0, 'repeat_on_month': False, 'repeat_on_year': False, 'mon': False, 'tue': False, 'wed': False, 'thu': False, 'fri': False, 'sat': False, 'sun': False, 'repeat_day': False,
'repeat_week': False, 'repeat_weekday': False, 'repeat_month': False, 'repeat_show_dow': False, 'repeat_show_day': False, 'repeat_show_week': False, 'repeat_show_month': False, 'analytic_account_id': [19,
'Office Design'], 'is_analytic_account_id_changed': False,
'project_analytic_account_id': [19, 'Office Design'], '__last_update': '2022-11-05 07:29:55', 'display_name': 'Office planning',
'create_uid': [1, 'OdooBot'], 'write_uid': [1, 'OdooBot']}]
To utilize the search read method, it is necessary to substitute the task IDs with the provided values.
task_ids = call(url, "object", "execute", database, uid, password, "project.task", "read", [1])
Create Records
Creating records in the database is achievable through JSON-RPC.
Here's the process for creating a record:
URL: Indicate the JSON-RPC URL by including the host and port number.
service: Define the service as an object.
method: Set the method to "execute."
args: Provide the necessary arguments for creating records.
project_args = {
'name': 'JSON_RPC Project 3'
}
project_id = call(url, "object", "execute", database, uid, password, "project.project", "create", project_args)
#Create task only if project is created
if project_id:
task_args = {
'name': 'JSON_RPC Task 1',
'project_id': project_id
}
task_id = call(url, "object", "execute", database, uid, password, "project.task", "create", task_args)
The screenshot below shows the project and task created.
Update Records
project_args = {
'name': 'JSON_RPC Project 3'
}
project_args_update = {
'name': 'JSON_RPC Project updated'
}
project_id = call(url, "object", "execute", database, uid, password, "project.project", "create", project_args)
#Create task only if project is created
if project_id:
project_update = call(url, "object", "execute", database, uid, password, "project.project", "write",project_id ,project_args_update)
It is used to update the records.
Delete Record
project_args = {
'name': 'JSON_RPC Project 3'
}
project_id = call(url, "object", "execute", database, uid, password, "project.project", "create", project_args)
#Create task only if project is created
if project_id:
project_update = call(url, "object", "execute", database, uid, password, "project.project", "unlink", [project_id] )
The record created through JSON-RPC can be deleted by employing the "unlink" method.
Calling Method
import json
import json
import random
import urllib.request
host = 'localhost'
port = 8017
database = 'Demo'
user = 'admin'
password = 'admin'
def json_rpc(url, method, params):
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": random.randint(0, 1000000000),
}
req = urllib.request.Request(url=url, data=json.dumps(data).encode(), headers={
"Content-Type":"application/json",
})
reply = json.loads(urllib.request.urlopen(req).read().decode('UTF-8'))
if reply.get("error"):
raise Exception(reply["error"])
return reply["result"]
def call(url, service, method, *args):
return json_rpc(url, "call", {"service": service, "method": method, "args": args})
url = "http://%s:%s/jsonrpc" % (host, port)
uid = call(url, "common", "login", database, user, password)
print(uid)
Specify the URL by including the host and port. Provide details such as the database name, user login, and password. Utilize the "service" and "common" with the "method" set to "login" to establish a connection with the Odoo database.