API trong Odoo - XML-RPC
Tut 9: API trong Odoo - XML-RPC
Trước khi xem bài viết này, bạn vui lòng hoàn thành hướng dẫn ở Tut 8: Thừa kế controller trong Odoo hoặc download mã nguồn ở cuối bài Tut 8.
Bài viết này sẽ hướng dẫn bạn:
- Thông tin về XML-RPC do Odoo cung cấp
- Gọi API của Odoo bằng XML-RPC
Odoo API: XML-RPC
XML-RPC là giao thức cho phép gọi thủ tục (procedure) từ xa đến backend - RPC (remote procedure call), thông qua XML.
Công tâm mà nói thì đây là giao thức đã "cũ kĩ"; Odoo đã hỗ trợ cung cấp web service này từ những phiên bản đầu tiên của Odoo. Đến bây giờ vẫn chưa có cải tiến gì mới mẻ, nhưng nó vẫn hoạt động tốt.
Tài liệu tham khảo chính thức của Odoo về XML-RPC: https://www.odoo.com/documentation/13.0/webservices/odoo.html
Gọi API của Odoo bằng XML-RPC
Sau khi biết sơ qua về XML-RPC, chúng ta hãy tiến hành thử sử dụng nó nhé.
Đầu tiên, bạn phải có một Odoo server đang chạy. Trên Odoo, Minh đã cài module my_pet như đã hướng dẫn ở cuối Tut 8. Bài thực hành này mình sẽ tiến hành viết một client nhỏ gọi Odoo server này để truy vấn thông tin thú cưng, cũng như thực hiện vài thao tác cơ bản như "insert", "update". Code ví dụ mình sẽ viết bằng Python 3 - xmlrpc là thư viện built-in.
Quy trình sử dụng XML-RPC:
- Xác thực với Odoo server. Bạn phải nắm đầy đủ các thông tin sau: URL web của Odoo, tên database, user name đăng nhập, mật khẩu của user đó.
import xmlrpc.client
url = 'https://<odoo-domain-name>/' # or 'http://localhost:8069/'
db = '<database name>'
username = '<user>'
password = '<password>'
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {}) # <- use it later
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url)) # <- user it later
- Thực hiện RPC đến một phương thức trong model của Odoo. Nếu đã xác thực thành công người dùng ở bước 1, bạn có thể gọi phương thức trong model của Odoo.
model_name = 'my.pet'
method = 'search_read'
param1 = [[('id', '>', 1)]]
param2 = {}
models.execute_kw(db, uid, password, model_name, method, param1, param2)
Xem thêm các ví dụ RPC bạn tham khảo link tài liệu của Odoo nhé: https://www.odoo.com/documentation/13.0/webservices/odoo.html
Mình có gói XML-RPC thành một class cho dễ dùng, mấy ông có thể tham khảo và sử dụng:
xml_rpc.py
import xmlrpc.client
ODOO_BACKEND = 'http://localhost:8069'
ODOO_DB = 'my_pet'
ODOO_USER = 'admin'
ODOO_PASS = 'admin'
def myprint(data_list, title=''):
if title:
print(title)
for line in data_list:
print('-', line)
pass
# https://www.odoo.com/documentation/13.0/webservices/odoo.html
class XMLRPC_API():
def __init__(self, url, db, username='admin', password='admin'):
self.url = url
self.db = db
self.username = username
self.password = password
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(self.url))
self.uid = common.authenticate(self.db, self.username, self.password, {})
self.models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(self.url))
pass
# get fields names of the model
def get_fields(self, model_name, required=False):
data = self.models.execute_kw(self.db,
self.uid,
self.password,
model_name,
'fields_get',
[], {'attributes': ['string', 'type', 'required', 'readonly']})
if required:
key_list = list(data.keys())
for k in key_list:
if not data[k].get('required', False):
data.pop(k)
pass
return data
def search(self, model_name, conditions=[()]):
return self.models.execute_kw(self.db, self.uid, self.password,
model_name,
'search',
[conditions])
# Create
def create(self, model_name, data_dict):
"""
Eg.
model_name: 'res.users'
data_dict: { 'name': "Minh", 'age': 27 }
"""
id = self.models.execute_kw(self.db, self.uid, self.password, model_name, 'create', [data_dict])
return id
# Read
def read(self, model_name, conditions=[()], params={}):
"""
Eg.
model_name: 'res.users'
conditions: [('id', '>', 1)]
params: {'fields': ['name', 'country_id', 'comment'], 'limit': 5}
"""
return self.models.execute_kw(self.db, self.uid, self.password,
model_name,
'search_read',
[conditions],
params)
# Update
def update(self, model_name, id_list, new_data_dict):
"""
Eg.
model_name: 'res.users'
id_list: [7]
new_data_dict: { 'name': "Newer partner", 'age': 27 }
"""
self.models.execute_kw(self.db,
self.uid,
self.password,
model_name,
'write',
[id_list, new_data_dict])
# Delete
def delete(self, model_name, id_list):
self.models.execute_kw(self.db, self.uid, self.password, model_name, 'unlink', [id_list])
pass
# Soft delete
def soft_delete(self, model_name, id_list):
self.update(model_name, id_list, {
'active': False,
})
# Aug 01, 2019
def call(self, model_name, method, params=[]):
return self.models.execute_kw(self.db, self.uid, self.password, model_name, method, params)
def call2(self, model_name, method, param1, param2):
return self.models.execute_kw(self.db, self.uid, self.password, model_name, method, param1, param2)
def main():
client = XMLRPC_API(url=ODOO_BACKEND, db=ODOO_DB, username=ODOO_USER, password=ODOO_PASS)
# list vendor accounts
myprint(client.read(model_name='my.pet',
conditions=[('id', '>=', 1)],
params={ 'fields': ['name', 'nickname'], }), title='Read My Pet')
myprint(client.call2(model_name="my.pet", method="search_read", param1=[[('id', '>=', 1)]], param2={}), title='General Call')
client.create(model_name="my.pet", data_dict={"name": "Minh", "nickname": "Kyz"})
print("Created new pet")
client.update(model_name="my.pet", id_list=[1], new_data_dict={"name": "Kitte", "nickname": "Sugar Baby"})
print("Update new pet")
pass
if __name__ == '__main__':
main()
Chạy bằng lệnh sau: python3 xml_rpc.py
Kết quả thực thi:
Read My Pet
- {'id': 1, 'name': 'Kitte', 'nickname': 'Sugar Baby'}
General Call
- {'product_ids': [], 'display_name': 'Kitte', 'description': False, 'write_date': '2020-08-23 08:14:12', 'basic_price': 0.0, 'write_uid': [2, 'Mitchell Admin'], 'weight': 0.0, 'pet_image': False, 'owner_id': [10, 'Deco Addict'], 'nickname': 'Sugar Baby', 'dob': False, 'create_date': '2020-08-19 14:38:04', 'age': 1, 'create_uid': [2, 'Mitchell Admin'], '__last_update': '2020-08-23 08:14:12', 'id': 1, 'name': 'Kitte', 'gender': 'male'}
Created new pet
Update new pet
Viết thành class rất tiện dụng, mấy ông có thể import
vào để sử dụng. Minh đã viết các hàm CRUD cho tiện sử dụng:
- Create: create()
- Read: read()
- Update: update()
- Delete: delete()
- Bonus: soft_delete() sẽ set field active bằng False, lúc này record vẫn nằm trong database nhưng nó ẩn khỏi các câu query => không hiển thị lên giao diện Odoo.
Sắp tới khi hoàn tất chỉnh chu, Minh sẽ bán một module cho phép expose JSON API một cách dễ dàng bằng cách thao tác trên giao diện Odoo. Khi đó mình sẽ thêm link module trên Odoo Apps vào bài viết này, để quý anh chị nào cần có thể mua về sử dụng cho dự án của mình. Hiện tại chưa có nhe, Minh chỉ nhá hàng trước thôi ^^; mong sẽ được mọi người ủng hộ.
Bài viết tiếp theo: Tut 10: Hiện thực wizard trong Odoo
- Khóa học lập trình Odoo TP.HCM: Thông tin và đăng ký khóa học
- Khảo sát nhu cầu học nghiệp vụ Odoo Offline @ HCM & đăng ký sớm: https://forms.gle/auBXLNbfuNqhJSbj8
Cài đặt Odoo:
- Docker Compose for Odoo 10
- Docker Compose for Odoo 11
- Docker Compose for Odoo 12
- Docker Compose for Odoo 13
- Docker Compose for Odoo 14
- Docker Compose for Odoo 15
- Docker Compose for Odoo 16
Danh sách bài viết series Odoo:
- Tut 0: Học lập trình Odoo - tutorials
- Tut 1: Odoo là gì?
- Tut 2: Hướng dẫn cài đặt Odoo version 10, 11, 12, 13
- Tut 3: Tạo model trong Odoo
- Tut 4: View trong Odoo
- Tut 5: Controller trong Odoo
- Tut 6: Thừa kế model trong Odoo
- Tut 7: Thừa kế view trong Odoo
- Tut 8: Thừa kế controller trong Odoo
- Tut 9: API trong Odoo - XML-RPC
- Tut 10: Hiện thực wizard trong Odoo
- Tut 11: Tạo widget trong Odoo
- Tut 12: Tạo settings trong Odoo cho custom addon
- Tut 13: Thêm button cho list/tree view trong Odoo
- Tut 14: Search, Filter, Group By trong Odoo
- Tut 15: Kết nối PostgreSQL database của Odoo bằng câu lệnh
- Tut 16: Kết nối pgAdmin vào PostgreSQL database của Odoo
Tham gia ngay group trên Facebook để cùng thảo luận với đồng bọn nhé:
- Fanpage Minh: https://www.facebook.com/minhng.info
- Khám phá Odoo: https://www.facebook.com/groups/odoo-dev
Khám phá Odoo