Controller trong Odoo

  Apr 11, 2020      2m
   

Tut 5: Odoo Controller

Controller trong Odoo

Trước khi xem bài viết này, bạn vui lòng hoàn thành hướng dẫn ở Tut 4 hoặc download mã nguồn ở cuối bài Tut 4. Bài viết này sẽ hướng dẫn bạn cách tạo mới một controller trong Odoo.

Mã nguồn hoàn chỉnh cho bài viết này được đính kèm ở cuối bài viết.

Tạo controller trong Odoo

Khai báo controller

Đầu tiên, ta tạo một thư mục controllers bên trong module mypet và trong đó chứa 2 file mới là __init__.py và main.py. Cấu trúc như sau:

mypet/controllers:

  • __init__.py
  • main.py

Đồng thời, ta phải khai báo trong file init để nó biết sự tồn tại của code Python trong controllers folder vừa tạo.

mypet/__init__.py:

from . import models
from . import controllers # <- them dong nay

Hiện thực Odoo controller

Trước khi hiện thực main.py, ta phải import code python này cái đã, bằng cách thêm dòng sau vào file init.

mypet/controllers/__init__.py:

from . import main

Rồi, đến đây là ta import xong xuôi các thủ tục "quy trình" cần thiết.

API đầu tiên - foo API

Main controller ta hiện thực như sau:

  • Khai báo class của chúng ta MyPetAPI kế thừa Odoo controller là http.Controller
  • Routing đường dẫn đến method mà sẽ đón nhận xử lý: route @ /foo -> foo_handler()
  • Trong hàm foo ta trả về chuỗi chào mừng. Bất kể bạn có đăng nhập vào Odoo hay không, vì ta đã đặc tả authpublic
  • Các thuộc tính của route() tham khảo thêm tại đây: https://www.odoo.com/documentation/13.0/reference/http.html#odoo.http.route

mypet/controllers/main.py:

import odoo
import logging
_logger = logging.getLogger(__name__)

class MyPetAPI(odoo.http.Controller):
    @odoo.http.route('/foo', auth='public')
    def foo_handler(self):
        return "Welcome to 'foo' API!"

Sau khi hiện thực API foo xong, ta restart Odoo server. Nếu bạn đang dùng docker-compose trên web Minh đã chỉ dẫn thì không cần restart vì bên trong đã thêm cờ tự động restart nếu code Python thay đổi.

Xem thành quả bằng cách mở trình duyệt tại localhost:10013/foo, được kết quả như hình dưới:

odoo controller - foo api returns

JSON API - bar API

Giờ ta muốn viết một bar API trả về dữ liệu dạng chuỗi json, để client có thể parse và xử lý ở frontend. Ta cần thêm vào main.py như sau:

mypet/controllers/main.py

...
import json
...
class MyPetAPI(odoo.http.Controller):
    ...
    @odoo.http.route('/bar', auth='public')
    def bar_handler(self):
        return json.dumps({
            "content": "Welcome to 'bar' API!"
        })

Mở trình duyệt tại localhost:10013/bar được kết quả:

{"content": "Welcome to 'bar' API!"}

API đọc dữ liệu từ Model

API này bặt đầu phức tạp hơn, ta muốn tạo một public API trả về thông tin của Pet. Như vậy controller của ta phải đón nhận được dẫn routing theo dạng /pet/<DBNAME>/<ID>, sau đó truy vấn model theo database name đọc ra dữ liệu và trả về chuỗi json. Ta sẽ tiến hành hiện thực theo code bên dưới:

mypet/controllers/main.py

... # import nhu tren
class MyPetAPI(odoo.http.Controller):
    ... # code nhu tren

    @odoo.http.route(['/pet/<dbname>/<id>'], type='http', auth="none", sitemap=False, cors='*', csrf=False)
    def pet_handler(self, dbname, id, **kw):
        model_name = "my.pet"
        try:
            registry = odoo.modules.registry.Registry(dbname)
            with odoo.api.Environment.manage(), registry.cursor() as cr:
                env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
                rec = env[model_name].search([('id', '=', int(id))], limit=1)
                response = {
                    "status": "ok",
                    "content": {
                        "name": rec.name,
                        "nickname": rec.nickname,
                        "description": rec.description,
                        "age": rec.age,
                        "weight": rec.weight,
                        "dob": rec.dob.strftime('%d/%m/%Y'),
                        "gender": rec.gender,
                    }
                }
        except Exception:
            response = {
                "status": "error",
                "content": "not found"
            }
        return json.dumps(response)

Giải thích:

  • Ta cần tham số dbname là bởi vì Odoo server cho phép tạo nhiều database, và mỗi database có một tên duy nhất không trùng nhau. Mình có thể kiểm tra tên database bằng cách mở chế độ debug lên, tên db sẽ ở cạnh tên user đang đăng nhập.
  • Trong phương thức pet_handler() ta mở môi trường kết nối đến bảng "my.pet" bằng account admin odoo.SUPERUSER_ID để tìm kiếm và đọc ra dữ liệu.
  • Trường hợp nếu có bất kỳ lỗi nào (exception) ta sẽ trả về response lỗi không tìm thấy.
  • Dữ liệu trả về sẽ bị lỗi nếu có Object trong đó, cụ thể trong ví dụ trên thì là trường rec.dob (ngày sinh của thú cưng), nó sẽ là DateTime object chẳng hạn, do đó ta phải chuyển đổi sang dạng string để tránh lỗi, sẵn tiện format luôn theo định dạng ngày/tháng/năm ta mong muốn.

Thử kiếm tra lại API mới viết xem sao:

Minh đã tạo database tên là tut5 (nhớ đổi lại theo tên database name của bạn đang thực hành trên máy), và tạo 1 record đầu tiên trên giao diện của module mypet (tut 4). Sau đó truy vấn theo URL sau:

$ curl http://localhost:10013/pet/tut5/1
{"status": "ok", "content": {"name": "Cat named Dog", "nickname": "Kyz", "description": "Pick from the street", "age": 1, "weight": 8.0, "dob": "08/01/2020", "gender": "male"}}
$ curl http://localhost:10013/pet/tut5/0
{"status": "error", "content": "not found"}
$ curl http://localhost:10013/pet/noexist_db/1
{"status": "error", "content": "not found"}

Download Tut 5 - Odoo Controller

Source code download: Tut 5 - Controller

Chuyên mục thảo luận cho Tut 5 @ https://www.facebook.com/groups/odoo.dev/learning_content/?filter=226430075118574&post=899424217189282


minhng.info dự định sẽ mở khóa học training lập trình Odoo OFFLINE ở TP. HCM, nếu bạn nào có nhu cầu giúp mình tham gia khảo sát nhé.

https://forms.gle/K9t2kjx5SCQWftkm8

Cài đặt Odoo:

Danh sách bài viết series Odoo:

Tham gia ngay group trên Facebook để cùng thảo luận với đồng bọn nhé: