Odoo Web前端界面詳解 - 1

近期準備對odoo web模塊進行一些整理,大致的說說odoo的前端界面是如何生成的,又是如何與後端交互,主要着重點就是odoo的js這塊的東西,由於odoo11的js代碼已經有了較大的改變,所以就以odoo11來分析吧。

爲了簡單敘述,暫時不考慮多個db的情況(主要是懶得說沒有db或者多個db實例的情況)當odoo指定數據庫開啓服務時(也就是odoo-bin -d <some_db_name> ),我們使用chrome的隱身模式訪問http://127.0.0.1:8069 ,此時打開chrome的開發者模式,查看Network可以看到,請求和相應如下

這裏寫圖片描述

1. 輸入http://127.0.0.1:8069/之後發生了什麼

192.168.56.102, 這個是我的虛機ip地址,返回響應是200,可以通過源代碼中, 我們看到

# web/controllers/main.py:435

@http.route('/', type='http', auth='none')
def index(self, s_action=None, db=None, **kwargs):
        return http.local_redirect('/web', query=request.params, keep_hash=True)

按照代碼命名來看,應該返回一個30x的redirect響應,爲什麼實際返回的確是200的響應頭呢?
繼續查看代碼,可以發現就是keep_hash=True 這個參數所引起的,在local_redirect 函數中由於keep_hash,

# odoo/http.py:156
def redirect_with_hash(url, code=303):
    if request.httprequest.user_agent.browser in ('firefox',):
        return werkzeug.utils.redirect(url, code)
    url = pycompat.to_text(url)
    if urls.url_parse(url, scheme='http').scheme not in ('http', 'https'):
        url = u'http://' + url
    url = url.replace("'", "%27").replace("<", "%3C")
    return "<html><head><script>window.location = '%s' + location.hash;</script></head></html>" % url

調用了redirect_with_hash 函數,而多數瀏覽器是不支持帶着hash redirect的,就直接返回了html,並且帶有script的js代碼,使得從js的角度實現帶有hash地址的redirect。
通過curl命令驗證,實際上確實是如此返回
這裏寫圖片描述

2. 跳轉至/web之後

繼續看代碼,

# web/controllers/main.py:442
@http.route('/web', type='http', auth="none")
def web_client(self, s_action=None, **kw):
    ensure_db()
    if not request.session.uid:
        return werkzeug.utils.redirect('/web/login', 303)
    if kw.get('redirect'):
        return werkzeug.utils.redirect(kw.get('redirect'), 303)

    request.uid = request.session.uid
    try:
        context = request.env['ir.http'].webclient_rendering_context()
        response = request.render('web.webclient_bootstrap', qcontext=context)
        response.headers['X-Frame-Options'] = 'DENY'
        return response
    except AccessError:
        return werkzeug.utils.redirect('/web/login?error=access')

ensure_db(),就是一些確定當前用戶是否選擇db,沒有就跳轉到/web/database/selector, 或者/web/database/create,由於上面我說了只使用一個db,因爲其他情況不想多講,所以在ensure_db中,默認替我們選擇好了唯一一個db,並且存在request.session中了。接下來,由於我們尚未登陸,request.session.uid爲空,就返回了 /web/login 303的響應。
這裏寫圖片描述

3. 跳轉至/web/login

代碼如下

# web/controllers/main.py:467
@http.route('/web/login', type='http', auth="none", sitemap=False)
def web_login(self, redirect=None, **kw):
    ensure_db()
    request.params['login_success'] = False

    # 如果是帶有redirect的get請求,並且session中有uid(也就是用戶已經登陸的情況下),返回redirect
    # 我們目前不是這個情況
    if request.httprequest.method == 'GET' and redirect and request.session.uid:
        return http.redirect_with_hash(redirect)

    # 設置request.uid
    if not request.uid:
        request.uid = odoo.SUPERUSER_ID

    values = request.params.copy()
    try:
        values['databases'] = http.db_list()
    except odoo.exceptions.AccessDenied:
        values['databases'] = None

    # 登陸的相關邏輯
    if request.httprequest.method == 'POST':
        old_uid = request.uid
        uid = request.session.authenticate(request.session.db, request.params['login'], request.params['password'])
        if uid is not False:
            request.params['login_success'] = True
            return http.redirect_with_hash(self._login_redirect(uid, redirect=redirect))
        request.uid = old_uid
        values['error'] = _("Wrong login/password")
    else:
        if 'error' in request.params and request.params.get('error') == 'access':
            values['error'] = _('Only employee can access this database. Please contact the administrator.')

    if 'login' not in values and request.session.get('auth_login'):
        values['login'] = request.session.get('auth_login')

    if not odoo.tools.config['list_db']:
        # 這個值決定了是否在登陸界面出現Manage Databases超鏈接
        values['disable_database_manager'] = True

    # GET請求,返回的響應就是這個了,
    response = request.render('web.login', values)
    response.headers['X-Frame-Options'] = 'DENY'
    return response

到這,就不得不提一下odoo自己的Qweb模板引擎了,這個'web.login',就是qweb view的id,具體可以通過全局查找定位到'web.login' 的位置,其實就是在web/views/webclient_templates.xml中301行的位置,qweb有它自己獨特的語法,這個要了解就去odoo官網查看吧,然後通過values對這個模板進行渲染,然後返回200的響應,就出現了基本的登錄界面了
這裏寫圖片描述

綜上,這就是基本的輸入界面到返回界面的一些過程。

例子 - 去除登陸頁面的Powered by Odoo鏈接

從上面的第3步,我們可以看到,最後登錄界面是由'web.login' 模板來顯示的,通過odoo的繼承方式,我們很容易的就可以去除這個鏈接,通過查找,這個鏈接實際是出現在'web.login_layout' qweb視圖中,

<template id='remove_login_odoo_link' inherit_id='web.login_layout'>
    <xpath expr='//div[@t-if="not disable_footer"]' position='replace'>
        <div class="text-right" t-if="not disable_footer">
            <t t-if="not disable_database_manager">
                <a class="" href="/web/database/manager">Manage Databases</a>
            </t>
        </div>
    </xpath>
</template>

全部代碼,查看 https://github.com/JZ10UJS/extra-addonsremove_login_odoo_link 模塊,

完成後,效果如下
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章