Типичная задача. Допустим, нам нужно принимать какие-то данные из внешнего источника, обрабатывать их и возвращать результат.
Я не буду описывать всю логику, а сконцентрируюсь лишь на основных моментах при работе с контроллерами в Odoo. Как обычно, все делаем в отдельном модуле.
Наш контроллер:
# -*- coding: utf-8 -*- from odoo import http class CustomPostRoute(http.Controller): @http.route('/custom-route/', auth='public') def index(self, **kw): return "OK"
Обратите внимание. Мы используем auth=’public’. Благодаря этому нам не нужна авторизация для доступа к странице.
После перехода по адресу /custom-route/ мы увидим следующее:
Сейчас наш URL доступен только по запросам: GET, HEAD, TRACE и OPTIONS. Это связано с тем, что начиная с Odoo 9 реализована CSRF защита.
Если отправить POST запрос, мы получим ошибку:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <title>400 Bad Request</title> <h1>Bad Request</h1> <p>Session expired (invalid CSRF token)</p>
Как отключить CSRF в Odoo?
Чтобы отключить CSRF для страницы, достаточно прописать в контроллере csrf=False. После этого, если мы отправим POST запрос, получим стандартный ответ «ОК».
Следующим действием, ограничим доступные методы. Разрешим только GET и POST запросы. В контроллере прописываем methods=[‘GET’, ‘POST’].
# -*- coding: utf-8 -*- from odoo import http class CustomPostRoute(http.Controller): @http.route('/custom-route/', auth='public', csrf=False, methods=['GET', 'POST']) def index(self, **kw): return "OK"
Теперь, если мы выполним любой другой метод, нас будет ожидать 405 ошибка с уведомлением, что этот метод запрещен.
Идем дальше. Давайте для каждого из методов будет возвращать разные ответы. Для этого получим значение метода, который используется и выведем разный текст:
# -*- coding: utf-8 -*- from odoo import http class CustomPostRoute(http.Controller): @http.route('/custom-route/', auth='public', csrf=False, methods=['GET', 'POST']) def index(self, **kw): request_method = http.request.httprequest.method if request_method == "GET": text = f"Запрос отправлен методом {request_method}!" else: request_data = 'не получены' text = f"Запрос отправлен методом {request_method}, данные: {request_data}." return text
Мы получили 2 разных текста, для каждого из запросов: «Запрос отправлен методом GET!» и «Запрос отправлен методом POST, данные: не получены.» Для пост запросов будем сохранять данные и выводить на экран в виде текста.
Как получить JSON данные в Odoo?
Чтобы получить JSON, нужно в контроллер добавить type=»json». По дефолту это значение равно «html». Теперь мы сможем принимать данные в JSON формате.
Учтите, что изменив type, у нас измениться Content-Type ответа. Вместо text/html будет application/json.
Пример POST запроса для Odoo с данными в json:
curl -i -X POST -H "Content-Type: application/json" -d '{"params": {"value":"8571519351"}}' 'localhost:8071/custom-route/'
Результатом:
HTTP/1.0 200 OK Content-Type: application/json Content-Length: 285 Set-Cookie: session_id=61f1b59ea1efba4c725708246946669c7677737a; Expires=Thu, 23-Apr-2020 20:33:39 GMT; Max-Age=7776000; HttpOnly; Path=/ Server: Werkzeug/0.14.1 Python/3.7.3 Date: Fri, 24 Jan 2020 20:33:39 GMT {"jsonrpc": "2.0", "id": null, "result": "\u0417\u0430\u043f\u0440\u043e\u0441 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043c\u0435\u0442\u043e\u0434\u043e\u043c POST, \u0434\u0430\u043d\u043d\u044b\u0435: \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b."}
Сервер возвращает JSON в формате {«jsonrpc»: «2.0», «id»: null, «result»: «наш ответ»}.
Добавим возможность сохранения данных и их отображения в строке:
# -*- coding: utf-8 -*- from odoo import http class CustomPostRoute(http.Controller): @http.route('/custom-route/', auth='public', csrf=False, methods=['GET', 'POST']) def index(self, **kw): request_method = http.request.httprequest.method if request_method == "GET": text = f"Запрос отправлен методом {request_method}!" else: request_data = str(http.request.params) text = f"Запрос отправлен методом {request_method}, данные: {request_data}." return text
При помощи http.request.params мы забираем значение params из отправленых данных.
Если нет возможности или желания изменить входные данные, так чтобы данные, которые мы отправляем уходили в {«params»: }, можно использовать другой способ:
# -*- coding: utf-8 -*- from odoo import http import json class CustomPostRoute(http.Controller): @http.route('/custom-route/', auth='public', csrf=False, methods=['GET', 'POST']) def index(self, **kw): request_method = http.request.httprequest.method if request_method == "GET": text = f"Запрос отправлен методом {request_method}!" else: request_data = str(http.request.params) if bool(request_data) == False: print(f"WORK WITH cache, {request_data}") _cached_data = http.request.httprequest._cached_data request_data = json.loads(_cached_data.decode('utf-8')) request_data = str(request_data) text = f"Запрос отправлен методом {request_method}, данные: {request_data}." return text
Как видите, мы проверяем, есть ли что-то в params. Если ничего нет, забираем http.request.httprequest._cached_data, конвертируем utf-8 и JSON.
Код в статье не претендует на звание самого лучшего или эффективного решения. Это просто пример на скорую руку, как создать собственный эндпоинт в Odoo.