odoo前后端交互详解
为了简单叙述,暂时不考虑多个db的情况(主要是懒得说没有db或者多个db实例的情况)当odoo指定数据库开启服务时(也就是odoo-bin -d <some_db_name>
),我们使用chrome的隐身模式访问http://127.0.0.1:8069
1. 输入http://127.0.0.1:8069/之后发生了什么
192.168.1.10, 这个是我的虚机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>
<odoo>
<data>
<template id="assets_backend" inherit_id="web.assets_backend" name="title assets backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/remove_login_odoo_link/static/src/title.js"></script>
</xpath>
</template> <!--移除/web/login界面中, Powered by Odoo的超链接-->
<template id='remove_login_odoo_link' inherit_id='web.login_layout'>
<xpath expr='//a[@href="https://www.odoo.com"]' position='replace'/>
<xpath expr="//t[@t-if='not disable_database_manager']" position="replace">
<a class="" href="/web/database/manager">Manage Databases</a>
</xpath>
</template> <!--替换/web/login下的 title-->
<template id='remove_web_head_title' inherit_id='web.layout'>
<xpath expr='//head/title' position='replace'>
<title t-esc="title"/>
</xpath>
</template> </data>
</odoo>
出现登陆界面,在我们输入用户名密码之后,odoo又做了什么,chrome中开发人员模式,看到请求如下
# web/controllers/main.py:483
# 登陆逻辑,
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
# 密码验证通过之后,返回一个带hash的响应,实际上是200响应头,js实现跳转到/web
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.') # 在/web route下
# web/controllers/main.py:443
@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) # /web/login成功之后的跳转,session已经有uid, 返回html
request.uid = request.session.uid
try:
# 获取当前用户的一些context,包括菜单之类的
context = request.env['ir.http'].webclient_rendering_context()
# 用模板渲染html
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')
简短就是,验证登陆用户名密码成功之后,将用户uid写入session之中,然后跳转至/web页面;/web请求时,获取用户的一些context包括能看到的菜单等,然后通过模板渲染,最后返回响应。 'web.webclient_bootstrap'模板可以在web/views/webclient_templates.xml:597行找到,通过模板我们可以看到只生成了一些基本的静态文件,以及当前登录用户的所能访问到的菜单。所有具体的页面内容都是后来由js处理和生成的。 所有的静态文件,如果没有开启debug=assets的话,都是由ir_qweb.py进行压缩成单独的一个js文件,当然其实有两个,一个是web.assets_common,一个是web.assets_backend(我们主要就是研究这个咯)
在webclient_templates.xml中找到id=’web.assets_backend’的template,和’web.assets_common’的template。 common里面导入一些通用的js文件,backend的js文件主要是登录成功后渲染/web里面内容所单独需要的。
odoo面试题---笔试题
1.什么是lambda函数?
Python的匿名函数lambda函数
lambda函数定义
python 使用 lambda 来创建匿名函数。lambda函数的语法只包含一个语句,如下:
参数 表达式
lambda [arg1 [,arg2,.....argn]]:expression
简单理解起来。匿名函数lambda是指一类无需定义标识符(函数名)的函数或子程序。
lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值。
lambda匿名函数的格式:冒号前是参数,可以有多个,用逗号隔开,冒号右边的为表达式。其实lambda返回值是一个函数的地址,也就是函数对象。
lambda函数实例
s=lambda x,y:x+y
h=lambda x,y,z:x+y-z
print(s(10,20),h(10,20,50))
lambda函数的特点和使用场景
特点
从函数命名的角度:匿名,直接返回可供调用的值
从输入输出的角度:支持多个输入参数,但只支持一个表达式
从函数功能的角度:结构简单,无须定义函数名。但所能实现的功能也极其受限。
从访问变量的角度:只支持访问lambda自己定义的变量。不支持外部变量访问
从运行效率的角度:lambda实际上仍开辟了一个内存单元,并没有提升运行效率
使用场景
lambda函数复制给变量:减少函数定义的麻烦,同时支持代码复用。
add=lambda x,y:x+y
print(add(1,2))
lambda函数赋值给函数:利用lambda函数实现对已有函数的重新定义。
例如,为了把标准库time中的函数sleep的功能屏蔽(Mock),我们可以在程序初始化时调用:time.sleep=lambda x:None。这样,在后续代码中调用time库的sleep函数将不会执行原有的功能。例如,执行time.sleep(3)时,程序不会休眠3秒钟,而是什么都不做。
利用lambda函数进行函数嵌套:利用lambda构造嵌套的内部和外部函数,实现闭包编程
部分Python内置函数接收函数作为参数。典型的此类内置函数有这些。
- filter函数。此时lambda函数用于指定过滤列表元素的条件。例如filter(lambda x: x % 3 == 0, [1, 2, 3])指定将列表[1,2,3]中能够被3整除的元素过滤出来,其结果是[3]。
- sorted函数。此时lambda函数用于指定对列表中所有元素进行排序的准则。例如sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))将列表[1, 2, 3, 4, 5, 6, 7, 8, 9]按照元素与5距离从小到大进行排序,其结果是[5, 4, 6, 3, 7, 2, 8, 1, 9]。
- map函数。此时lambda函数用于指定对列表中每一个元素的共同操作。例如map(lambda x: x+1, [1, 2,3])将列表[1, 2, 3]中的元素分别加1,其结果[2, 3, 4]。
- reduce函数。此时lambda函数用于指定列表中两两相邻元素的结合条件。例如reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])将列表 [1, 2, 3, 4, 5, 6, 7, 8, 9]中的元素从左往右两两以逗号分隔的字符的形式依次结合起来,其结果是'1, 2, 3, 4, 5, 6, 7, 8, 9'。
原文链接:https://blog.csdn.net/zhanshen112/article/details/90603865
2.如何判断一个对象的类型
a = 10 利用python的type()函数, print(type(a)) 输出:int
3.字典和json数据的转换
字典与json转化主要用到以下方法: loads():将json数据转化成dict数据
dumps():将dict数据转化成json数据
字典转json数据:
In [5]: import json
In [6]: dict = {'name':'mary','age':21}
In [7]: type(dict)
Out[7]: dict
In [8]: j = json.dumps(dict)
In [9]: j
Out[9]: '{"name": "mary", "age": 21}'
这里需要注意的是,如果字典转json时包含汉字,就会出现编码问题,如下:
In [29]: staff = {'name':'权权','age':23,'sex':'女'}
In [30]: json.dumps(staff)
Out[30]: '{"name": "\\u6743\\u6743", "age": 23, "sex": "\\u5973"}'
1
2
3
4
5
所以如果有中文,我们需要加参数处理:
In [31]: json.dumps(staff,ensure_ascii=False)
Out[31]: '{"name": "权权", "age": 23, "sex": "女"}'
原因:通常用post方式请求时是json数据,但如果有中文则显示有问题,因为中文用 unicode 编码,而默认却是用ASCII解析的,中文不在ASCII编码中,所以不能显示中文。
json数据转字典:
In [25]: j
Out[25]: '{"name": "mary", "age": 21}'
In [26]: result = json.loads(j)
In [27]: result
Out[27]: {'name': 'mary', 'age': 21}
In [28]: type(result)
Out[28]: dict
4.列表和元组的转换
元组 和 列表之间的转换 使用 list 函数 可以把 元组 转换成 列表 list(元组) 使用 tuple 函数 可以把 列表 转换成 元组 tuple(列表) #列表转换元组
num_list = [1,2,3,4,5]
print(type(num_list))
print(num_list)
num_tuple = tuple(num_list)
print(type(num_tuple))
print(num_tuple) #元组转换列表
num_tuple_01 = (1,2,3,4,5)
print(type(num_tuple_01))
print(num_tuple_01)
num_list_01 = list(num_tuple_01)
print(type(num_list_01))
print(num_list_01)
5.使用labana输出两数相乘
value=lambda x,y:x×y
print(value(1,2))
6.一行代码输出1-100之和
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information. range左闭右开区间
>>> total=sum(range(101))
>>> print (total)
5050
7.[[1, 2], [3, 4], [5, 6]]输出为[1, 2, 3, 4, 5, 6]
#1)利用推导式运行过程:for i in a ,每个i是【1,2】,【3,4】,【5,6】,for j in i,每个j就是1,2,3,4,5,6,合并后就是结果 a=[[1,2],[3,4],[5,6]]
x=[j for i in a for j in i] #这个的解析过程是 从a中取出每一个值付给i,然后从i中取出每一个 值复制给j 然后输出j的结果
print(x) ==>[1, 2, 3, 4, 5, 6]
8.列表去交集和并集
求多个list的交集 1 a = [0,1,2,3,4]
2 b = [0,2,6]
3 c = [-1,2,5,8]
4 r = list(set(a).intersection(b,c))
5 print('r -->', r) 求多个list的并集 1 a = [0,1,2,3,4]
2 b = [0,2,6]
3 c = [-1,2,5,8]
4 r = list(set(a).union(b,c)) # 求多个list的并集
5 print('r -->', r) # 输出:r --> [0, 1, 2, 3, 4, 5, 6, 8, -1]"""
求多个list的差(补)集 - 即获取特定1个list中有,其他list都没有的元素
1 a = [0,1,2,3,4]
2 b = [0,2,6]
3 c = [-1,2,5,8]
4 r = list(set(a).difference(b,c)) # 求特定1个list(a)中有,其他list(b、c)都没有的元素"""
5 print('r -->', r) # 输出:r --> [1, 3, 4]"""
list基本操作
1 list = [1, 2, 3]
2 list.append(5)
3 print(list)
4
5 list.extend([6, 7]) # extend是将可迭代对象的元素依次加入列表
6 print(list)
7
8 list.append([6, 7]) # append是把传入的参数当成一个元素加入列表
9 print(list)
10
11 list.reverse() # 元素翻转,注意不能将这个操作赋给一个变量,此操作是对list本身操作,即list自身发生变化
12 # l=list.reverse() l为空,没有得到list翻转后的值
13 print(list)
原文链接:https://blog.csdn.net/J_z10/article/details/79247533
odoo前后端交互详解的更多相关文章
- Node之简单的前后端交互
node是前端必学的一门技能,我们都知道node是用的js做后端,在学习node之前我们有必要明白node是如何实现前后端交互的. 这里写了一个简单的通过原生ajax与node实现的一个交互,刚刚学n ...
- Django之META与前后端交互
Django之META与前后端交互 1 提交表单之GET 前端提交数据与发送 1)提交表单数据 2)提交JSON数据 后端的数据接收与响应 1)接收GET请求数据 2)接收POST请求数据 3)响应请 ...
- 前后端交互实现(nginx,json,以及datatable的问题相关)
1.同源问题解决 首先,在同一个域下搭建网络域名访问,需要nginx软件,下载之后修改部分配置 然后再终端下cmd nginx.exe命令,或者打开nginx.exe文件,会运行nginx一闪而过, ...
- springboot+mybatis+thymeleaf项目搭建及前后端交互
前言 spring boot简化了spring的开发, 开发人员在开发过程中省去了大量的配置, 方便开发人员后期维护. 使用spring boot可以快速的开发出restful风格微服务架构. 本文将 ...
- 百度ueditor的图片上传,前后端交互使用
百度ueditor的使用 一个文本编辑器,看了网上很多文档写的很乱,这里拾人牙慧,整理下怎么使用. 这个东西如果不涉及到图片附件上传,其实很简单,就是几个前端文件,直接引用,然后配置下ueditor. ...
- SSM-网站后台管理系统制作(4)---Ajax前后端交互
前提:Ajax本身就为前后端交互服务的,实现功能:用户输入信息,实时判断用户的情况,这也是现在登录界面普遍流行的做法.前端js通过注释识别Controller层,该层查询返回,和之前Google验证码 ...
- 【HANA系列】SAP HANA XS使用JavaScript数据交互详解
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用Jav ...
- 【开源.NET】 轻量级内容管理框架Grissom.CMS(第二篇前后端交互数据结构分析)
这是 CMS 框架系列文章的第二篇,第一篇开源了该框架的代码和简要介绍了框架的目的.作用和思想,这篇主要解析如何把sql 转成标准 xml 配置文件和把前端post的增删改数据规范成方便后台解析的结构 ...
- thinkphp+jquery+ajax前后端交互注册验证
thinkphp+jquery+ajax前后端交互注册验证,界面如下 register.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. ...
随机推荐
- 基于webpack5封装的cli工具packx
安装 用 npm / yarn 安装: $ npm install -D packx $ yarn add -D packx 特性 基于 webpack5 支持 less,sass 支持 spa/mp ...
- 孟老板 Paging3 (二) 结合Room
BaseAdapter系列 ListAdapter系列 Paging3 (一) 入门 Paging3 (二) 结合 Room Paging3 (二) 结合Room Paging 数据源不开放, 无法 ...
- 【.NET 与树莓派】LED 数码管驱动模块——TM1638
LED 数码管,你可以将它看做是 N 个发光二级管的组合,一个灯负责显示一个段,七个段组合一位数字,再加一个小数点,这么一来,一位数码管就有八段.一般,按照顺时针的方向给每个段编号. 上图中的 h 就 ...
- Redisson 分布式锁源码 02:看门狗
前言 说起 Redisson,比较耳熟能详的就是这个看门狗(Watchdog)机制. 本文就一起看看加锁成功之后的看门狗(Watchdog)是如何实现的? 加锁成功 在前一篇文章中介绍了可重入锁加锁的 ...
- jenkins pipeline的声明式与脚本式
自从Jenkins 2.0 版本升级之后,支持了通过代码(Groovy DSL)来描述一个构建流水线,灵活方便地实现持续交付,大大提升 Jenkins Job 维护的效率,实现从 CI 到 CD 到转 ...
- 4.QT:spinbox(spindoublebox)控件的信号响应
Qt的QSpinBox和QDoubleSpinBox两个控件在默认情况下是valueChanged信号,会响应每次输入栏的改变. 比如想要输入数值"123",我们会依次键入1 - ...
- .obj : error LNK2019: 无法解析的外部符号
记录一个报错 .obj : error LNK2019: 无法解析的外部符号 "public: void __thiscall 习惯上先去看看 | "#include"语 ...
- hdu 2604 递推 矩阵快速幂
HDU 2604 Queuing (递推+矩阵快速幂) 这位作者讲的不错,可以看看他的 #include <cstdio> #include <iostream> #inclu ...
- 一小时搞懂Mysql锁机制
内容概述: 我们知道,数据也是一种供许多用户共享访问的资源.如何保证数据并发访问的一致性.有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素.从这一角度来说,锁对 ...
- 获取 Windows 密码「GitHub 热点速览 v.21.28」
作者:HelloGitHub-小鱼干 安全问题一直是 GitHub 的一大热点,因为数据安全问题诞生的各类自托管服务便是.而本周周榜上的 2 个和安全主题相关的项目,有些不同.mimikatz 是个老 ...