Session
本章基于Odoo18.0
OWL中的Session
我们先来看OWL的session代码的定义:
export const session = odoo.__session_info__ || {};
delete odoo.__session_info__;
这是session.js中的全部代码,看起来极其简单。 先定义了一个session的常量,然后删除了odoo.session_info这个中间变量。
那么这个odoo.session_info又是在哪里定义的呢?
<template id="web.webclient_bootstrap">
<t t-call="web.layout">
<t t-set="head_web">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
<meta name="theme-color" content="#71639e"/>
<link rel="manifest" href="/web/manifest.webmanifest" crossorigin="use-credentials"/>
<link rel="apple-touch-icon" href="/web/static/img/odoo-icon-ios.png"/>
<script type="text/javascript">
// Block to avoid leaking variables in the script scope
{
odoo.__session_info__ = <t t-out="json.dumps(session_info)"/>;
const { user_context, cache_hashes } = odoo.__session_info__;
const lang = new URLSearchParams(document.location.search).get("lang");
let menuURL = `/web/webclient/load_menus/${cache_hashes.load_menus}`;
if (lang) {
user_context.lang = lang;
menuURL += `?lang=${lang}`
}
odoo.reloadMenus = () => fetch(menuURL).then(res => res.json());
odoo.loadMenusPromise = odoo.reloadMenus();
// Prefetch translations to speedup webclient. This is done in JS because link rel="prefetch"
// is not yet supported on safari.
fetch(`/web/webclient/translations/${cache_hashes.translations}?lang=${user_context.lang}`);
}
</script>
<t t-call-assets="web.assets_web_print" media="print" t-js="false"/>
<t t-if="request.cookies.get('color_scheme') == 'dark'">
<t t-call-assets="web.assets_web_dark" media="screen"/>
</t>
<t t-else="">
<t t-call-assets="web.assets_web" media="screen"/>
</t>
<t t-call="web.conditional_assets_tests" media="screen"/>
</t>
<t t-set="head" t-value="head_web + (head or '')" media="screen"/>
<t t-set="body_classname" t-value="'o_web_client'"/>
</t>
</template>
我们在WC的视图代码中找到了session_info的定义。我们看到session_info是通过json.dumps()方法从session_info这个变量中出来的。那么我们下一步就要找到session_info这个变量是如何而来的了。
对于Backend来说,是由控制器在调用 request.render() 时放进渲染上下文:
from odoo import http
from odoo.http import request
class WebClient(http.Controller):
@http.route('/web', type='http', auth='user')
def web_client(self, **kw):
session_info = request.env['ir.http'].get_webclient_session_info()
# 这里把 session_info 作为变量传给模板
return request.render('web.webclient_bootstrap', {
'session_info': session_info,
'debug': request.debug,
# 其他上下文字段...
})
对于fronted来说,则是由前端页面直接调用:
<script type="text/javascript">
odoo.__session_info__ = <t t-out="json.dumps(request.env['ir.http'].get_frontend_session_info())"/>;
</script>
ir.http模型内部:
class IrHttp(models.AbstractModel):
_name = 'ir.http'
def get_webclient_session_info(self):
# 返回后台需要的完整 session 信息
return {
'user_context': request.context,
'cache_hashes': self._get_asset_hashes(),
# 还有 uid, user_company, companies 等字段
}
def get_frontend_session_info(self):
# 返回前端(门户)精简版 session 信息
return {
'user_context': request.context,
'cache_hashes': self._get_asset_hashes(),
# 精简字段集合
}
因此,如果我们想要通过后台给前端session_info中传入额外的变量,则需要继承ir.http模型的相应的方法完成。