1、 django、flask、tornado框架的比较
1
2
3
4
5
6
|
django是一个大而全的Web框架,它内部提供了很多组件:ORM,admin,Form,ModelForm,分页,缓冲等,只要在配置文件一修改就能应用起来,
对于flask来说,它是一个轻量级的,短小精悍、可扩展强 的一个Web框架,适用于开发小型的网站,也能开发大型网站,因为它为我们
提供了很多第三方的组件,把flask与这些第三方组件结合起来也可以创造出一个跟django类似的集成了很多功能的框架,所以flask的可定制性比较强。
Tornado:少而精(轻量级框架),注重性能优越,速度快,解决高并发(请求处理是基于回调的非阻塞调用),异步非阻塞,websockets 长连接总结:要性能, Tornado 首选;要开发速度,Django 和 Flask 都行,区别是 Flask 把许多功能交给第三方库去完成了,因此 Flask 更为灵活。
|
2、 什么是wsgi
1
2
3
4
5
6
|
WSGI全称为Python Web Server Gateway Interface,Python Web服务器网关接口,它是介于Web服务器和Web应用程序(或Web框架)之间的一种简单而通用的接口。
我们知道,客户端和服务器端之间进行沟通遵循HTTP协议。但是我们用Python所编写的很多Web程序,并不会直接去处理HTTP请求,因为这太复杂了。
所以WSGI诞生了,使从HTTP请求和Web程序之间,多了一种转换过程——从HTTP报文转换成WSGI的数据格式。
这个时候,我们的Web程序就可以建立在WSGI之上,直接去处理WSGI解析给我们的请求,而我们就可以专注于Web程序本身的编写。
|
3、 django请求的生命周期
1
2
3
4
5
6
7
8
9
|
用户请求-->--> wsgi, 它就是socket服务端,用于接收用户请求并将请求进行初次封装,然后将请求交给web框架(Flask、Django)
--> 中间件,帮助我们对请求进行校验或在请求对象中添加其他相关数据,例如:csrf、request.session
--> url路由匹配 ,找到视图里面的函数或者类
--> 视图函数,在视图函数中进行业务逻辑的处理,可能涉及到:orm、templates => 渲染
--> 中间件,对响应的数据进行处理。
--> wsgi,将响应的内容发送给浏览器。
补充:我们拿到的request其实是经过了两次封装,第一次是到达wsgi对请求的数据进行初次封装,然后到达Django再次进行封装
|
用户请求进来先走到 wsgi,
然后将请求交给 Django的中间件,穿过中间件(方法是process_request),
接着就是路由匹配,路由匹配成功之后就执行相应的视图函数,在视图函数中可以调用orm做数据库操作,
再从模板路径将模板拿到,然后在后台进行模板渲染,模板渲染完成之后就变成一个字符串,再把这个字符串经过所有中间件(方法:process_response)和wsgi 返回给用户
4、列举django的内置组件?
1
2
3
4
5
|
1·admin组件:对model中对应的数据表进行增删改查
2·model组件:负责操作数据库
3·form组件:生成html代码,数据有效性检验信息返回并展示
4·ModelForm组件:用于数据库操作,也可用于用户请求的验证5 分页器组件
|
5、列举 django中间件的5个方法 ?以及django中间件的应用场景 ?
1
2
3
4
5
6
7
8
|
process_request : 请求进来时,权限认证
process_view :在urls.py中找到对应关系之后 在执行真正的视图函数之前process_exception : 异常时执行 process_template_responseprocess : 模板渲染时执行 process_response : 请求有响应时执行
正是由于一个请求HttpRequest在传递给视图View处理前要经过中间件处理,经过View处理后的响应也要经过中间件处理才能返回给用户,我们可以编写自己的中间件实现权限校验,限制用户请求、打印日志、改变输出内容等多种应用场景,比如:
1、禁止特定IP地址的用户或未登录的用户访问我们的View视图函数2、对同一IP地址单位时间内发送的请求数量做出限制
3、在View视图函数执行前记录用户的IP地址4、在View视图函数执行前传递额外的变量或参数
5、在View视图函数执行前或执行后把特定信息打印到log日志6、在View视图函数执行后对reponse数据进行修改后返回给用户另外一种使用场景:比如说,在 Web 开发中视图经常需要返回 JSON 数据。但是由于需求的不同,因此数据结构很难统一。此时,可以利用中间件对响应对象再做一层包装,统一数据结构,可以利用 process_response 函数完成。
|
6、简述什么是FBV和CBV
1
2
3
4
5
6
7
8
9
|
FBV(function base views) 在视图里使用函数处理请求。在之前django的学习中,我们一直使用的是这种方式。
CBV(class base views) 就是在视图里使用类处理请求。
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:
-提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
-可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
|
区别:
- 没什么区别,因为他们的本质都是函数。CBV的.as_view()返回的view函数,view函数中调用类的dispatch方法,在dispatch方法中通过反射执行get/post/delete/put等方法。
非要说区别的话:
- CBV比较简洁,GET/POST等业务功能分别放在不同get/post函数中。FBV自己做判断进行区分。
7、django的request对象 是在什么时候创建的?
1
2
3
4
|
class WSGIHandler(base.BaseHandler):
-------request = self.request_class(environ)
请求走到WSGIHandler类的时候,执行cell方法,将environ封装成了request
|
8、如何给CBV的程序添加装饰器?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from django.utils.decorators import method_decorator
1、给方法加:
@method_decorator(check_login)
def post(self, request):
...
2、给dispatch加:
@method_decorator(check_login)
def dispatch(self, request, *args, **kwargs):
...
3、给类加:
@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):
...
|
9、列举django orm 中所有的方法(QuerySet对象的所有方法)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<1> all(): 查询所有结果
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象。获取不到返回None
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个。
如果符合筛选条件的对象超过一个或者没有都会抛出错误。
<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
<5> order_by(*field): 对查询结果排序
<6> reverse(): 对查询结果反向排序
<8> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
<9> first(): 返回第一条记录
<10> last(): 返回最后一条记录
<11> exists(): 如果QuerySet包含数据,就返回True,否则返回False
<12> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的
并不是一系 model的实例化对象,而是一个可迭代的字典序列
<13> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<14> distinct(): 从返回结果中剔除重复纪录
|
10、 only和defer的区别 ?
1
2
3
4
5
6
7
|
#only:只取model表中的某n列
queryset = [object,object]
result = model.User.objects.all().only('id','name')
for item in result:
print(item.id,item.name) #想取什么要在only中先获取,不然查询性能会降低
#defer:不取表中的哪些列
|
11、 select_related和prefetch_related的区别
1
2
3
4
|
前提:有外键存在时,可以很好的减少数据库请求的次数,提高性能
select_related通过多表join关联查询,一次性获得所有数据,只执行一次SQL查询,如果连表多,性能越来越差。支持 o2o ,ForeignKey
prefetch_related分别查询每个表,然后根据它们之间的关系进行处理,执行两次查询。支持m2m
|
12、filter和exclude的区别?
1
2
|
两者取到的值都是QuerySet对象,filter选择满足条件的,exclude:排除满足条件的.
|
13、列举django orm中三种能写sql语句的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
1.使用execute执行自定义的SQL
直接执行SQL语句(类似于pymysql的用法)
# 更高灵活度的方式执行原生SQL语句
from django.db import connection
cursor = connection.cursor()
cursor.execute("SELECT DATE_FORMAT(create_time, '%Y-%m') FROM blog_article;")
ret = cursor.fetchall()
print(ret)
2.使用extra方法 :queryset.extra(select={"key": "原生的SQL语句"})
3.使用raw方法
1.执行原始sql并返回模型
2.依赖model多用于查询
|
14、django orm 中如何设置读写分离?
1
2
3
|
方式一:手动使用queryset的using方法
方式二:写配置文件
|
15、 F和Q的作用
1
2
3
4
|
F对象:可以使用模型的字段A与字段B进行比较,如果A写在了等号的左边,则B出现在等号的右边,需要通过F对象构造;
Q对象:Q对象实例化后能够增加各个条件之间的关系,而且这种写法用在你不知道用户到底传入了多少个参数的时候很方便。
比如默认情况下filter()里面每个字段的连接都是&,我们使用Q对象通常都是让它变成|,来进行查询 。
|
16、values和values_list的区别?
1
2
3
4
5
6
7
8
|
values:
values(*fields)
返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。每个字典表示一个对象,键对应于模型对象的属性名称。
values_list:
values_list(*fields, flat=False) #values_list方法加个参数flat=True可以获取number的值列表。
与values() 类似,只是在迭代时返回的是元组而不是字典。每个元组包含传递给values_list() 调用的字段的值 —— 所以第一个元素为第一个字段,以此类推。
|
17、如何使用django orm批量创建数据 ?
1
2
3
4
5
6
7
|
# 批量插入数据的时候,首先要创建一个对象的列表,然后调用bulk_create方法,一次将列表中的数据插入到数据库中。
product_list_to_insert = list()
for x in range(10):
product_list_to_insert.append(Product(name='product name ' + str(x), price=x))
Product.objects.bulk_create(product_list_to_insert)
|
18、django的Form和ModeForm的作用?
1
2
3
4
5
6
7
8
9
|
我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息。
Django form组件就实现了上面所述的功能。
总结一下,其实form组件的主要功能如下:
生成页面可用的HTML标签
对用户提交的数据进行校验
保留上次输入内容
提供错误信息ModelForm组件的功能就是把model和form组合起来,使用更加方便
|
19、django的Form组件中,如果字段中包含choices参数,请使用两种方式实现数据源实时更新。
!img View Code
20、django的Model中的ForeignKey字段中的on_delete参数有什么作用?
1
2
3
|
删除关联表中的数据时,当前表与其关联的field的操作
django2.0之后,表与表之间关联的时候,必须要写on_delete参数,否则会报异常
|
21、django中csrf的实现机制?
1
2
3
4
|
第一步:django第一次响应来自某个客户端的请求时,后端随机产生一个token值,把这个token保存在SESSION状态中;同时,后端把这个token放到cookie中交给前端页面;
第二步:下次前端需要发起请求(比如发帖)的时候把这个token值加入到请求数据或者头信息中,一起传给后端;Cookies:{csrftoken:xxxxx}
第三步:后端校验前端请求带过来的token和SESSION里的token是否一致。
|
Django预防CSRF攻击的方法是在用户提交的表单中加入一个csrftoken的隐含值,这个值和服务器中保存的csrftoken的值相同,这样做的原理如下:
1、在用户访问django的可信站点时,django反馈给用户的表单中有一个隐含字段csrftoken,这个值是在服务器端随机生成的,每一次提交表单都会生成不同的值
2、当用户提交django的表单时,服务器校验这个表单的csrftoken是否和自己保存的一致,来判断用户的合法性
3、当用户被csrf攻击从其他站点发送精心编制的攻击请求时,由于其他站点不可能知道隐藏的csrftoken字段的信息这样在服务器端就会校验失败,攻击被成功防御
具体配置如下:
template中添加{%csrf_token%}标签
22、django如何实现websocket?
1
2
3
|
django实现websocket官方推荐大家使用channels。channels通过升级http协议 升级到websocket协议。保证实时通讯。也就是说,我们完全可以用channels实现我们
的即时通讯。而不是使用长轮询和计时器方式来保证伪实时通讯。他通过改造django框架,使django既支持http协议又支持websocket协议。
|
23、基于django使用ajax发送post请求时,都可以使用哪种方法携带csrf token?
1
2
3
4
5
6
7
8
9
10
11
|
#1.后端将csrftoken传到前端,发送post请求时携带这个值发送
data: {
csrfmiddlewaretoken: '{{ csrf_token }}'
},
#2.获取form中隐藏标签的csrftoken值,加入到请求数据中传给后端
data: {
csrfmiddlewaretoken:$('[name="csrfmiddlewaretoken"]').val()
},
#3.cookie中存在csrftoken,将csrftoken值放到请求头中
headers:{ "X-CSRFtoken":$.cookie("csrftoken")}
|
24、django中如何实现orm表中添加数据时创建一条日志记录。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 使用Django的信号机制,可以在添加、删除数据前后设置日志记录:
pre_init # Django中的model对象执行其构造方法前,自动触发
post_init # Django中的model对象执行其构造方法后,自动触发
pre_save # Django中的model对象保存前,自动触发
post_save # Django中的model对象保存后,自动触发
pre_delete # Django中的model对象删除前,自动触发
post_delete # Django中的model对象删除后,自动触发
# 使用
@receiver(post_save, sender=Myclass) # 信号接收装饰器。由于内置信号,所以直接接收
def signal_handler(sender, **kwargs): # 接收到信号后,在此处理
logger = logging.getLogger()
logger.success('保存成功')
|
25、django缓存如何设置?
1
2
|
Django 的缓存配置是通过 setting 文件的 CACHES 配置来实现的。
|
26、django的缓存能使用redis吗?如果可以的话,如何配置?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#1,django中应用redis缓存需要先安装第三方库 django-redis
#2,settings.py文件中进行配置
CACHES = {
# default 是缓存名,可以配置多个缓存 默认缓存名为default
"default": {
# 应用 django-redis 库的 RedisCache 缓存类
"BACKEND": "django_redis.cache.RedisCache",
# 配置正确的 ip和port
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
# redis客户端类
"CLIENT_CLASS": "django_redis.client.DefaultClient",
# redis连接池的关键字参数
"CONNECTION_POOL_KWARGS": {
"max_connections": 100
}
# 如果 redis 设置了密码,那么这里需要设置对应的密码,如果redis没有设置密码,那么这里也不设置
# "PASSWORD": "123456",
}
},
#注意:可配置多个缓存,前面的缓存后面加逗号
"default2": {
},
}
|
27、django路由系统中name的作用?
1
2
|
name 可以用于在 templates, models, views ……中得到对应的网址,相当于“给网址取了个小名”,只要这个名字不变,网址变了也能通过名字获取到。
|
28、django的模板中filter和simple_tag的区别?
1
2
3
4
5
|
simple_tag
-参数任意,但是不能作为if条件判断的条件
filter
-参数最多只能有两个,但是可以作为if条件判断的条件。
|
29、django-debug-toolbar的作用?
1
2
|
django_debug_toolbar 是django的第三方工具包,给django扩展了调试功能。 包括查看执行的sql语句,db查询次数,request,headers,调试概览等。
|
30、django中如何实现单元测试?
31、解释orm中 db first 和 code first的含义?
1
2
3
4
|
数据持久化的方式:
db first基于已存在的数据库,生成模型
code first基于已存在的模型,生成数据库库
|
32、django中如何根据数据库表生成model中的类?
1
2
3
4
5
6
|
1.在settings中设置要连接的数据库
2.生成model模型文件
python manage.py inspectdb
3.模型文件导入到models中
python manage.py inspectdb > app/models.py
|
33 使用orm和原生sql的优缺点?
1
2
3
|
1.orm的开发速度快,操作简单。使开发更加对象化,执行速度慢。处理多表联查等复杂操作时,ORM的语法会变得复杂
2.sql开发速度慢,执行速度快。性能强
|
34、简述MVC和MTV
1
2
3
|
MVC: 模型 视图 控制器
MTV: 模型 模板 视图
|
35、django的contenttype组件的作用?
1
2
3
|
这个组件保存了项目中所有app和model的对应关系,每当我们创建了新的model并执行数据库迁移后,ContentType表中就会自动新增一条记录
当一张表和多个表FK关联,并且多个FK中只能选择其中一个或其中n个时,可以利用contenttypes
|
36、谈谈你对restfull 规范的认识?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
首先restful是一种软件架构风格或者说是一种设计风格,并不是标准,它只是提供了一组设计#原则和约束条件,主要用于客户端和服务器交互类的软件。
#就像设计模式一样,并不是一定要遵循这些原则,而是基于这个风格设计的软件可以更简洁,更#有层次,我们可以根据开发的实际情况,做相应的改变。
它里面提到了一些规范,例如:
1.restful 提倡面向资源编程,在url接口中尽量要使用名词,不要使用动词
2、在url接口中推荐使用Https协议,让网络接口更加安全:https://www.bootcss.com/v1/mycss?page=3
(Https是Http的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL(安全套接层协议))
3、在url中可以体现版本号:https://v1.bootcss.com/mycss ,不同的版本可以有不同的接口,使其更加简洁,清晰
4、url中可以体现是否是API接口 :https://www.bootcss.com/api/mycss
5、url中可以添加条件去筛选匹配 :https://www.bootcss.com/v1/mycss?page=3
6、可以根据Http不同的method,进行不同的资源操作:(5种方法:GET / POST / PUT / DELETE / PATCH)
7、响应式应该设置状态码
8、有返回值,而且格式为统一的json格式
9、返回错误信息:返回值携带错误信息
10、返回结果中要提供帮助链接,即API最好做到Hypermedia,如果遇到需要跳转的情况 携带调转接口的URL
ret = {
code: 1000,
data:{
id:1,
name:'小强',
depart_id:http://www.luffycity.com/api/v1/depart/8/
}
}
|
37、接口的幂等性是什么意思?
1
2
3
|
1.是系统的接口对外一种承诺(而不是实现)
2.承诺只要调用接口成功,外部多次调用对系统的影响都是一致的,不会对资源重复操作
|
36、什么是RPC?
1
2
3
4
5
6
|
远程过程调用 (RPC) 是一种协议,程序可使用这种协议向网络中的另一台计算机上的程序请求服务
1.RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。
2.首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。
2.在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,
3.最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。
|
39、Http和Https的区别?
1
2
3
|
超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
|
40、为什么要使用django rest framework框架?
1
2
3
4
5
6
7
8
9
10
11
|
1.客户端-服务端分离
优点:提高用户界面的便携性,通过简化服务器提高可伸缩性….
2.无状态(Stateless):从客户端的每个请求要包含服务器所需要的所有信息
优点:提高可见性(可以单独考虑每个请求),提高了可靠性(更容易从局部故障中修复),提高可扩展性(降低了服务器资源使用)
3.缓存(Cachable):服务器返回信息必须被标记是否可以缓存,如果缓存,客户端可能会重用之前的信息发送请求
优点:减少交互次数,减少交互的平均延迟
4.统一接口
优点:提高交互的可见性,鼓励单独改善组件
5.支持按需代码(Code-On-Demand 可选)
优点:提高可扩展性
|
能自动生成符合 RESTful 规范的 API
1.在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本一样,这部分的代码可以简写
2.在序列化与反序列化时,虽然操作的数据不同,但是执行的过程却相似,这部分的代码也可以简写,
REST framework可以帮助简化上述两部分的代码编写,大大提高REST API的开发速度
41、django rest framework框架中都有那些组件?
1
2
3
4
5
6
7
8
9
10
11
12
|
1.序列化组件:serializers 对queryset序列化以及对请求数据格式校验
2.路由组件routers 进行路由分发
3.视图组件ModelViewSet 帮助开发者提供了一些类,并在类中提供了多个方法
4.认证组件 写一个类并注册到认证类(authentication_classes),在类的的authticate方法中编写认证逻
5.权限组件 写一个类并注册到权限类(permission_classes),在类的的has_permission方法中编写认证逻辑。
6.频率限制 写一个类并注册到频率类(throttle_classes),在类的的allow_request/wait 方法中编写认证逻辑
7.解析器 选择对数据解析的类,在解析器类中注册(parser_classes)
8.渲染器 定义数据如何渲染到到页面上,在渲染器类中注册(renderer_classes)
9.分页 对获取到的数据进行分页处理, pagination_class
10.版本 版本控制用来在不同的客户端使用不同的行为
在url中设置version参数,用户请求时候传入参数。在request.version中获取版本,根据版本不同 做不同处理
|
42、django rest framework框架中的视图都可以继承哪些类?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class View(object):
class APIView(View): 封装了view,并且重新封装了request,初始化了各种组件
class GenericAPIView(views.APIView):
1.增加了一些属性和方法,如get_queryset,get_serializer
class GenericViewSet(ViewSetMixin, generics.GenericAPIView)
父类ViewSetMixin 重写了as_view,返回return csrf_exempt(view)
并重新设置请求方式与执行函数的关系
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):pass
继承了mixins下的一些类,封装了list,create,update等方法
和GenericViewSet
|
43、简述 django rest framework框架的认证流程。
1
2
3
4
|
1.用户请求走进来后,走APIView,初始化了默认的认证方法
2.走到APIView的dispatch方法,initial方法调用了request.user
3.如果我们配置了认证类,走我们自己认证类中的authentication方法
|
44、django rest framework如何实现的用户访问频率控制?
1
2
3
4
|
使用IP/用户账号作为键,每次的访问时间戳作为值,构造一个字典形式的数据,存起来,每次访问时对时间戳列表的元素进行判断,
把超时的删掉,再计算列表剩余的元素数就能做到频率限制了
匿名用户:使用IP控制,但是无法完全控制,因为用户可以换代理IP登录用户:使用账号控制,但是如果有很多账号,也无法限制
|
45、Django本身提供了runserver,为什么不能用来部署?(runserver与uWSGI的区别)
1
2
3
|
1.runserver方法是调试 Django 时经常用到的运行方式,它使用Django自带的WSGI Server 运行,主要在测试和开发中使用,并且 runserver 开启的方式也是单进程 。
2.uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http 等协议。注意uwsgi是一种通信协议,而uWSGI是实现uwsgi协议和WSGI协议的 Web 服务器。 uWSGI具有超快的性能、低内存占用和多app管理等优点,并且搭配着Nginx就是一个生产环境了,能够将用户访问请求与应用 app 隔离开,实现真正的部署 。 相比来讲,支持的并发量更高,方便管理多进程,发挥多核的优势,提升性能。
|
46、cookie和session的区别
1
2
3
4
|
1、cookie是保存在浏览器端的键值对,而session是保存的服务器端的键值对,但是依赖cookie。(也可以不依赖cookie,可以放在url,或请求头但是cookie比较方便)
2、以登录为例,cookie为通过登录成功后,设置明文的键值对,并将键值对发送客户端存,明文信息可能存在泄漏,不安全;session则是生成随机字符串,发给用户, 并写到浏览器的cookie中,同时服务器自己也会保存一份。
3、在登录验证时,cookie:根据浏览器发送请求时附带的cookie的键值对进行判断,如果存在,则验证通过;session:在请求用户的cookie中获取随机字符串,根据随机 字符串在session中获取其对应的值进行验证
|
二、Flask
45、Flask框架的优势?
Flask框架的优势包括轻量级、灵活性高、容易上手、可扩展性好、能够自由选择需要的功能模块等。其设计理念简单明了,结构清晰,易于维护和开发。
46、Flask框架依赖组件?
Flask框架主要依赖组件包括Werkzeug、Jinja2以及标准库中的一些模块,如json、datetime等。其中,Werkzeug提供了基本的网络请求和响应处理功能,Jinja2则用于模板渲染。
Werkzeug是一个WSGI工具库,可以打造高效的Python web应用程序,包括路由调度器、服务器兼容性、RequestResponse对象等,使用它可以方便地实现HTTP请求的处理。
Jinja2是一种现代化的,基于模板的视图引擎,它轻便、可扩展,并易于使用。Jinja2支持在模板中使用标记、变量、宏、继承模板、模板包含等多种特性,可以将应用数据与HTML模板进行简单、高效的结合。
1
2
3
4
5
6
7
8
9
10
| python
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def template_test():
return render_template('test.html', my_string='Flask Template Demo', my_list=[0,1,2,3,4,5])
if __name__ == '__main__':
app.run(debug=True)
|
47、Flask蓝图的作用?
Flask蓝图是一种将应用程序分解为多个模块的机制。通过使用蓝图,可以更好地组织代码,将不同模块的功能分离,提高代码复用性和可扩展性。此外,蓝图还可以配合Flask提供的上下文管理机制,使得应用的代码可以更加优雅地编写。
使用Flask蓝图创建子应用并处理对应的请求:
在蓝图文件夹内进行路由配置。假设Blueprint目录下有一个user.py文件
user.py
1
2
3
4
5
6
7
| python
from flask import Blueprint, render_template
user = Blueprint('user', __name__)
@user.route('/user/<name>')
def user_index(name):
return render_template('user.html', name=name)
|
在主程序上注册该蓝图对象,并设定其前缀为/user,表示该蓝图处理 访问/user的请求:
app.py
1
2
3
4
5
6
7
8
| python
from flask import Flask
from user import user
app = Flask(__name__)
app.register_blueprint(user, url_prefix='/user')
if __name__ == '__main__':
app.run(debug=True)
|
48、列举使用过的Flask第三方组件?
使用过的Flask第三方组件包括Flask-WTF、Flask-Login、Flask-Mail、Flask-RESTful等。其中,Flask-WTF提供了表单处理功能,Flask-Login提供了用户认证和授权功能,Flask-Mail提供了电子邮件发送功能,Flask-RESTful提供了RESTful API设计和实现功能。
49、简述Flask上下文管理流程?
Flask上下文管理流程包括应用上下文和请求上下文两个部分。应用上下文在应用启动时创建,且只有一个实例,在整个应用的生命周期中一直存在。请求上下文则是在每次请求到来时动态创建,同时也会建立一个应用上下文,然后将请求处理完毕后将上下文清除。
使用Flask app_context 和 request_context定义上下文:
app_context
1
2
3
4
5
6
| python
from flask import Flask, current_app
app = Flask(__name__)
with app.app_context():
a = current_app.config['DEBUG']
|
request_context
1
2
3
4
5
6
7
8
| python
from flask import Flask, request
app = Flask(__name__)
with app.test_request_context('/?name=Flask'):
# now we can interact with the request object
assert request.method == 'GET'
assert request.args['name'] == 'Flask'
|
50、Flask中的g的作用?
Flask中的g是一个全局变量,用于存储在请求处理过程中需要跨函数共享的数据。通过在请求上下文中加入g对象,可以方便地在处理某个请求的各个函数之间共享数据。g对象的具体实现是通过Local对象实现的,保证了并发情况下线程安全。示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| python
from flask import Flask, g
app = Flask(__name__)
@app.route('/')
def index():
g.user = 'guest'
return 'Hello World!'
@app.route('/user')
def user():
return 'User:{}'.format(g.user)
if __name__ == '__main__':
app.run()
|
51、Flask中上下文管理主要涉及到了那些相关的类?并描述类主要作用?
Flask中上下文管理主要涉及到了AppContext和RequestContext两个类。AppContext是在应用启动时创建的上下文对象,用于存储与应用相关的数据,如配置、数据库连接等。RequestContext则是在每个请求到达时动态创建的上下文对象,一般包括请求信息、Session对象、用户身份验证信息等,以及请求处理完成后需要清除的数据。这两个类都实现了固定的生命周期,并可用于统一地处理请求流程中所涉及的上下文管理逻辑。
52、为什么要Flask把Local对象中的的值stack 维护成一个列表?
Flask把Local对象中的值维护成一个列表是为了应对可能存在的并发请求处理,因为在Flask中应用的运行是在一个单进程中处理多个请求,如果不维护成列表,多个请求使用同一对象进行共享数据时就会存在冲突,无法保证数据的准确性和合理性。
53、Flask中多app应用是怎么完成?
在Flask中,多app应用一般使用Blueprint构建。Blueprint是一种轻量级应用分解机制,类似于多App开发模式,将应用的功能模块进行划分独立开发,提高了应用的可读性和可扩展性。
54、在Flask中实现WebSocket需要什么组件?
在Flask中实现WebSocket需要使用Flask-SocketIO组件。Flask-SocketIO是Flask的一个扩展包,是一个基于WebSocket的实时通信工具,具有实时消息传输功能。Flask-SocketIO不仅可以实现同一服务器运行多个应用程序之间的实时通信,还可以实现跨域浏览器之间的实时通信。
55、wtforms组件的作用?
wtforms是一个用Python编写的,用于处理web表单的模块,使用它可以有效地管理web应用程序中的表单。使用wtforms,可以方便地实现表单的验证和数据处理,一般为每个表单创建一个类,类的属性即表单中的各个字段,然后通过表单验证等操作将表单数据存储至数据库中。wtforms不仅支持Flask框架,还可以在Django、Tornado等Web框架中使用。
56、Flask框架默认session处理机制?
Flask框架默认采用基于cookie的session机制。即将session数据存储在客户端浏览器的cookie中,每次请求时携带该cookie进行会话的维持。在Flask中,session存储在全局的flask.session对象中,在请求上下文中通过session属性获取。
Flask框架默认session处理机制的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| python
from flask import Flask, session
app = Flask(__name__)
app.secret_key = 'your_secret_key'
@app.route('/')
def hello_world():
if 'username' in session:
return 'Hello, {}'.format(session['username'])
else:
session['username'] = 'Flask User'
return 'Session created'
if __name__ == '__main__':
app.run()
|
在上述代码中,我们首先创建一个名为app的Flask应用程序,并设置应用程序的秘密密钥。接着,在路由函数中使用session来创建、读取和更新用户会话的数据。
57、解释Flask框架中的Local对象和threading.local对象的区别?
在Flask框架中,Local对象是一个线程本地对象,可以在不同线程中共享同一个变量,每个线程对该变量进行修改不会影响其他线程。而threading.local对象也是线程本地对象,每个线程拥有自己的一个拷贝,并且只能被该线程所访问和修改。Local对象相比线程本地对象的优点在于能够在多个线程之间共享同一个变量,因此在实现线程池等场景中更为适合。
58、Flask中 blinker 是什么?
Blinker是一个独立于Flask的Python库,主要用于事件驱动编程,支持发布-订阅模式和信号编程。在Flask框架中,Blinker模块被用于实现Flask信号系统。Flask在程序执行过程中会发出多个信号,如请求开始、请求完成等,我们可以通过监听这些信号来进行相关的操作。使用Blinker能够将这一机制扩展到自定义的应用程序事件上。Blinker通过创建实现观察者设计模式的信号对信号的接收者进行通知。使用Blinker,可以实现解耦合、让应用程序更加灵活的目的。
Flask中blinkers的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| python
from flask import Flask
from blinker import Namespace
app = Flask(__name__)
my_signals = Namespace()
@my_signals.connect('my_signal')
def my_signal_handler(sender, **kwargs):
print('Signal received from', sender, 'with data:', kwargs)
@app.route('/')
def hello_world():
my_signals.signal('my_signal').send('app', data='Flask')
if __name__ == '__main__':
app.run()
|
在上述代码中,我们使用Blinker建立了一个名为my_signals的命名空间,并定义了一个名为my_signal的信号。接着,我们为my_signal信号注册了my_signal_handler()函数作为信号接收者。最后,在路由函数中使用my_signals.signal(‘my_signal’).send()方法对my_signal信号进行了发送,并将data参数设置为Flask。当信号被发送时,my_signal_handler()函数将被调用,打印出信号的参数和数据。
59、SQLAlchemy中的 session和scoped_session 的区别?
在SQLAlchemy中,session是一个线程安全的操作数据库的对象。scoped_session是一个创建session工厂的工厂,用来创建可重用的、在多个线程之间共享的session实例。scoped_session有一个额外的优势,在数据库连接断开时,它会自动重新连接数据库,而不需要重新创建一个新的session。scoped_session适用于需要多次调用session进行操作的场景,能够减少创建和释放session的开销,提高了数据库访问效率。
60、SQLAlchemy如何执行原生SQL?
在SQLAlchemy中,可以通过session.execute()方法执行原生SQL。下面是一个简单的示例:
1
2
3
4
5
| python
from sqlalchemy import create_engine, text
engine = create_engine('mysql+pymysql://username:password@localhost:port/database')
result = engine.execute(text('SELECT * FROM table_name WHERE column_name = :value'), value='some_value')
|
在上述代码中,我们首先使用create_engine()方法连接到数据库。然后,通过text()函数传入原生SQL语句,使用execute()方法执行SQL查询。可以使用冒号(:)传递参数,最后返回查询结果。
61、ORM的实现原理?
ORM(Object-Relational Mapping) 实现原理是将关系型数据库中的表与 Python 类相对应,将表中的每一列字段映射为类变量,将行对应到使用类的对象,并将表之间的关系映射为对象之间的关系。ORM 隐藏了 SQL 语句细节,通过提供一套对数据库的面向对象 API 接口,在不需要编写 SQL 语句的情况下进行 CRUD 操作。ORM本质上就是将面向对象和关系数据库之间建立映射关系,屏蔽掉底层数据库的操作,能够使开发者更加专注于业务的处理,提高开发效率。
假设我们有一个数据库中的user表,包含id、name、age三个字段。我们可以通过ORM框架将这个user表映射为一个Python类:
1
2
3
4
5
6
7
8
9
10
11
12
13
| python
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('mysql+pymysql://user:password@host:port/database')
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(64))
age = Column(Integer)
|
在上述代码中,我们使用SQLAlchemy ORM框架定义了一个名为User的Python类,该类对应于数据库中的user表。使用Column类声明类属性,可以方便地将Python类属性映射到数据库表的列。在定义完成Python类之后,我们可以使用ORM框架提供的API对数据库进行增删改查等操作。例如,可以通过以下代码创建会话并插入一条新记录:
1
2
3
4
5
6
| python
Session = sessionmaker(bind=engine)
session = Session()
user = User(name='Alice', age=18)
session.add(user)
session.commit()
|
在此示例中,默认的Session是由SQLAlchemy的工厂函数sessionmaker生成的,使用绑定的引擎(engine)创建一个线程本地的session对象。我们定义了一个名为user的实例,将数据插入到数据库表中,最后使用commit()方法进行批量提交操作。ORM框架会自动将Python对象与数据库表进行关联,不需要编写SQL语句。
62、DBUtils模块的作用?
DBUtils 是一个常用的 Python 数据库连接工具,封装了 Python 的 DB-API 接口,并提供了连接池等一些操作数据库的高级功能。DBUtils 最主要的作用是提供了一种数据库连接池机制,可以在应用程序中复用已经建立好的连接对象,避免因连接对象的创建和销毁所带来的性能开销,提高应用程序的效率。
下面是使用DBUtils连接池进行数据库操作的一个示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| python
import pymysql
from dbutils.pooled_db import PooledDB
# 创建连接池
pool = PooledDB(
creator=pymysql,
maxconnections=5, # 连接池允许的最大连接数,0和None表示不限制连接数
mincached=0, # 初始化时,连接池中至少创建的空闲的连接,0表示不创建
maxcached=3, # 连接池中最多闲置的连接,0和None不限制
host='localhost',
port=3306,
user='root',
password='root',
db='test',
charset='utf8mb4'
)
# 获取连接
conn = pool.connection()
cursor = conn.cursor()
# 查询数据
sql = 'SELECT * FROM user WHERE age > %s'
cursor.execute(sql, (18,))
result = cursor.fetchall()
for row in result:
print(row)
# 插入数据
sql = 'INSERT INTO user(name, age) VALUES (%s, %s)'
values = [('Alice', 20), ('Bob', 22), ('Charlie', 25)]
for v in values:
cursor.execute(sql, v)
conn.commit()
# 关闭连接
cursor.close()
conn.close()
|
在上述代码中,我们使用DBUtils的PooledDB类创建了一个名为pool的连接池,并使用该连接池获取了一个名为conn的数据库连接。使用cursor对象可以执行SQL语句并获取查询结果。在执行完SQL语句后,我们需要手动提交事务,以确保数据已经写入数据库。最后,我们需要关闭cursor和conn,同时归还连接到连接池中。使用连接池可以避免频繁地创建和销毁连接对象,提高访问数据库的效率。
63、以下SQLAlchemy的字段是否正确?如果不正确请更正:
1
2
3
4
5
6
7
8
9
10
11
12
|
from datetime import datetime
from sqlalchemy.ext.declarative
import declarative_base
from sqlalchemy import Column, Integer, String, DateTime
Base = declarative_base()
class UserInfo(Base):
__tablename__ = 'userinfo'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(64), unique=True)
ctime = Column(DateTime, default=datetime.now())
|
该代码中的字段定义是正确的。在该代码中,我们定义了一个名为UserInfo的类,它继承了SQLAlchemy中的Base类。该类表示一个名为userinfo的数据表,其中包括id、name和ctime三个字段,分别表示记录的唯一标识、用户姓名和创建时间。id字段被定义为自增的主键,name字段被定义为唯一的字符串类型,ctime字段被定义为日期时间类型,且默认为当前时间。这些字段的定义可以与SQLAlchemy ORM进行无缝集成,使用面向对象的方法进行数据库的CURD操作。
64、SQLAchemy中如何为表设置引擎和字符编码?
在SQLAlchemy中,可以使用create_engine函数初始化数据库连接,从而设置表的引擎和字符编码。create_engine函数可以接收URL或参数形式的输入。URL语法如下:
数据库类型 + 数据库驱动名称 : // 用户名 : 密码 @ 主机 : 端口 / 数据库名称 ? charset = 编码类型
参数形式如下:
create_engine(database_URL, **options)
其中,options 含有许多可选参数,可用于设置编码、服务器类型、连接池大小以及社交需求,如下所示:
1
2
3
| python
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:pass@localhost:3306/test?charset=utf8')
|
在上述代码中,我们使用MYSQL数据库的pymysql库作为连接驱动,指定了连接的用户名和密码,而URL中的"charset=utf8"参数则设置了数据库中默认的字符集为UTF-8
65、SQLAchemy中如何设置联合唯一索引?
在SQLAlchemy中,可以使用UniqueConstraint对类中的字段进行设置,以实现多列联合唯一约束。下面是一个示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| python
from sqlalchemy import create_engine, Column, Integer, String, UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('postgresql://user:password@localhost/mydatabase')
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
username = Column(String(50), nullable=False)
email = Column(String(120), unique=True, nullable=False)
# 联合唯一索引
__table_args__ = (UniqueConstraint('username', 'email', name='uix_username_email'),)
|
在上述代码中,使用UniqueConstraint对username和email字段进行了联合唯一约束设置,并指定约束名称为"uix_username_email"。使用该方式,可以在SQLAlchemy ORM中方便地实现多列联合唯一约束。
三、Tornado
比如你是一个高级软件开发工程师,回答说重点,要准确,体现你的经验,技能。如果有代码,代码放code区里。每个问题回答125字以内。
简述Tornado框架的特点。
简述Tornado框架中Future对象的作用?
Tornado框架中如何编写WebSocket程序?
Tornado中静态文件是如何处理的?如: <link href="{{static_url(“commons.css”)}}" rel=“stylesheet” />
Tornado操作MySQL使用的模块?
Tornado操作redis使用的模块?
简述Tornado框架的适用场景?
git常见命令作用:
以下是一些常见的 Git 命令
- git clone:从远程 Git 仓库中克隆代码到本地。
1
2
| git clone https://github.com/project1.git```
2. git pull:从远程 Git 仓库获取最新的更改并更新本地仓库。
|
git pull origin develop```Text only
- git branch:列出目前在本地仓库存在的分支。
1
2
3
| git branch```Text only
4. git checkout:切换到指定分支。
|
git checkout my_feature```Text only
- git checkout -b:创建一个新的分支并对其进行切换。
1
2
3
| git checkout -b my_feature```Text only
6. git add:向暂存区提交文件或文件夹的更改。
|
git add file1.txt```Text only
- git commit:将更改提交到本地仓库并创建一个新的提交记录。
1
2
3
| git commit -m "Added feature 1"```Text only
8. git push:将本地仓库的更改推送到远程 Git 仓库。
|
git push origin my_feature```Text only
- git merge:将目标分支合并到当前分支。
1
2
3
| git merge master```Text only
10. git status:检查当前分支并显示有关分支中存在的任何挂起更改的信息。
|
git status```Text only
- git log:查看 Git 仓库的提交历史记录。
1
2
3
| git log```Text only
12. git diff:显示当前分支和目标分支之间的差异。
|
git diff my_feature master```Text only
- git stash:将未提交的更改保存到堆栈中,以便可以更改分支或回滚更改。
1
2
3
| git stash```Text only
14. git stash pop:从 git 堆栈中恢复最近保存的更改。
|
git stash pop```Text only
- git reset:取消之前的提交并将主分支重置为指定的提交。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
| git reset --hard commit_hash```
简述以下git中stash命令作用以及相关其他命令。
git 中 merge 和 rebase命令 的区别。
公司如何基于git做的协同开发?
如何基于git实现代码review?
git如何实现v1.0 、v2.0 等版本的管理?
什么是gitlab?
github和gitlab的区别?
如何为github上牛逼的开源项目贡献代码?
git中 .gitignore文件的作用?
什么是敏捷开发?
简述 jenkins 工具的作用?
公司如何实现代码发布?
简述 RabbitMQ、Kafka、ZeroMQ的区别?
RabbitMQ如何在消费者获取任务后未处理完前就挂掉时,保证数据不丢失?
RabbitMQ如何对消息做持久化?
RabbitMQ如何控制消息被消费的顺序?
以下RabbitMQ的exchange type分别代表什么意思?如:fanout、direct、topic。
简述 celery 是什么以及应用场景?
简述celery运行机制。
celery如何实现定时任务?
简述 celery多任务结构目录?
celery中装饰器 @app.task 和 @shared_task的区别?
简述 requests模块的作用及基本使用?
简述 beautifulsoup模块的作用及基本使用?
简述 seleninu模块的作用及基本使用?
scrapy框架中各组件的工作流程?
在scrapy框架中如何设置代理(两种方法)?
scrapy框架中如何实现大文件的下载?
scrapy中如何实现限速?
scrapy中如何实现暂定爬虫?
scrapy中如何进行自定制命令?
scrapy中如何实现的记录爬虫的深度?
scrapy中的pipelines工作原理?
scrapy的pipelines如何丢弃一个item对象?
简述scrapy中爬虫中间件和下载中间件的作用?
scrapy-redis组件的作用?
scrapy-redis组件中如何实现的任务的去重?
scrapy-redis的调度器如何实现任务的深度优先和广度优先?
简述 vitualenv 及应用场景?
简述 pipreqs 及应用场景?
在Python中使用过什么代码检查工具?
简述 saltstack、ansible、fabric、puppet工具的作用?
B Tree和B+ Tree的区别?
请列举常见排序并通过代码实现任意三种。
请列举常见查找并通过代码实现任意三种。
请列举你熟悉的设计模式?
有没有刷过leetcode?
列举熟悉的的Linux命令。
公司线上服务器是什么系统?
解释 PV、UV 的含义?
解释 QPS的含义?
uwsgi和wsgi的区别?
supervisor的作用?
什么是反向代理?
简述SSH的整个过程。
有问题都去那些找解决方案?
是否有关注什么技术类的公众号?
最近在研究什么新技术?
是否了解过领域驱动模型?
正则问题:
notepad++ 是否可以实现 删除 超链接。图片链接除外 比如 [简述](https://zhutdd.test.com/p/153385581) 这个超链接 , 只保留中括号里的内容 其它都删掉 剩下简述。
输入正则表达式:在查找和替换对话框中,将“查找模式”设置为“正则表达式”,然后在“查找内容”中输入以下正则表达式:\[(.*?)\]\(.*?\)。
执行替换操作:在“替换内容”中输入 \1,然后单击“全部替换”按钮,执行替换操作。
在正则表达式中,\1 表示匹配到的第一个子组(即第一个用括号括起来的部分)。在这个示例中,我们使用 \[(.*?)\]\(.*?\) 匹配 Markdown 文件中的超链接,其中 \[(.*?)\] 匹配链接文本,.*? 匹配链接地址。我们将匹配到的链接文本替换为 \1,这样就可以删除链接地址和括号,只保留链接文本。
例如,如果我们有一个 Markdown 文件中的超链接是 [简述](https://zhutdd.test.com/p/153385581),那么正则表达式 \[(.*?)\]\(.*?\) 将匹配到 [简述](https://zhutdd.test.com/p/153385581),并将链接文本 简述 存储在第一个子组中。然后,我们将匹配到的链接文本替换为 \1,这样就可以删除链接地址和括号,只保留链接文本 简述。
|