面试知识点汇总

面试知识点汇总

一、django请求生命周期html

更新时间:前端

2018/6/25 18:04vue

- wsgi, 他就是socket服务端,用于接收用户请求并将请求进行初次封装,而后将请求交给web框架 (Flask、Django)python

- 中间件,帮助咱们对请求进行校验或在请求对象中添加其余相关数据,例如:csrf、request.session - 路由匹配 根据浏览器发送的不一样url去匹配不一样的视图函数
- 视图函数,在视图函数中进行业务逻辑的处理,可能涉及到:orm、templates => 渲染
- 中间件,对响应的数据进行处理。 mysql

- wsgi,将响应的内容发送给浏览器。 git

二、什么是wsgi 中文名:web服务器网关接口 实现该协议的模块: github

- wsgiref
- werkzurg - uwsgi web

PythonWeb服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是Python应用程序或框 架和Web服务器之间的一种接 口,是一种协议,实现该协议的模块有uwsgi、wsgiref和werkzeug,这些模 块本质上就是socket服务端,用于接收用户请求并将请求进行初次封装,而后将请求交给web框架 (Flask、Django) 面试

三、FBV和CBV本质是同样的,没有优劣之分,可根据不一样的需求来使用 视图 ajax

- FBV 基于函数的视图 url - 函数

- CBV 基于类的视图 url - view

四、restful 规范(10) 什么是接口?

- URL - 约束

# 约束继承(实现)了他的类中必须含有IFoo中的方法 interface

IFoo:
def func(self): pass

class Foo(IFoo): def func(self):

 

print(11111)

五、restful 10大规范: 首先restful是一种软件架构风格或者说是一种设计风格,并非标准,它只是提供了一组设计原则

和约束条件,主要用于客户端和服务器交互类的软件。
 就像设计模式同样,并非必定要遵循这些原则,而是基于这个风格设计的软件能够更简洁,更有层
次,咱们能够根据开发的实际状况,
 作相应的改变。它里面提到了一些规范,例如:

一、在url接口中推荐使用Https协议,让网络接口更加安全(Https是Http的安全版,即HTTP下加入 SSL层,HTTPS的安全基础是SSL,所以加密的详细内容就须要SSL(安全套接层协议))

二、url中能够体现这是个API接口 三、url中还能够体现版本号,不一样的版本能够有不一样的接口,使其更加简洁,清晰
四、restful 提倡面向资源编程,因此在url接口中尽可能要使用名词,不要使用动词 五、此外url中还能够添加条件去筛选匹配 六、能够根据Http不一样的method,进行不一样的资源操做(5种方法:GET / POST / PUT / DELETE

/ PATCH) 七、响应式应该包含状态码

1) 200 OK - [GET]:服务器成功返回用户请求的数据,该操做是幂等的(Idempotent)。 2) 201 CREATED -[POST/PUT/PATCH]:用户新建或修改数据成功。
3) 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
4) 204 NO CONTENT - [DELETE]:用户删除数据成功。

5) 400 INVALID REQUEST -[POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行 新建或修改数据的操做,该操做是幂等的。

6) 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
7) 403 Forbidden - [*] 表示用户获得受权(与401错误相对),可是访问是被禁止的。
8) 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操做,该

操做是幂等的。
9) 406 Not Acceptable - [GET]:用户请求的格式不可得(好比用户请求JSON格式,可是只有

XML格式)。
10) 410Gone -[GET]:用户请求的资源被永久删除,且不会再获得的。
11) 422Unprocesable entity - [POST/PUT/PATCH] 当建立一个对象时,发生一个验证错误。 12) 500INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将没法判断发出的请求是否

成功。
八、应该有返回值,并且格式为统一的json格式 九、应该返回错误信息 十、返回结果中要提供帮助连接,即API最好作到Hypermedia。

六、rest framework框架(10大组件)&& 谈谈你对 django rest framework框架的认识? - 路由,

- 能够经过as_view传参数,根据请求方式不一样执行相应的方法

- 能够在url中设置一个结尾,相似于: .json - 视图,

- 帮助开发者提供了一些类,并在类中提供了多个方法以供咱们使用。 - 版本,

- 在url中设置version参数,用户请求时候传入参数。在request.version中获取版本,根据版本不一样 作不一样处理

 

- 认证,
- 写一个类并注册到认证类,在类的的authticate方法中编写认证逻辑。

- 认证成功(user,auth) - raise AuthticateFaild(....) - None

- 权限
- 写一个类并注册到权限类,在类的的has_permission方法中编写认证逻辑。

- True

- False - 频率限制

- 写一个类并注册到频率类,在类的的 allow_request/wait 方法中编写认证逻辑。 allow_request

- True

- False 若是返回False,那么就要执行wait - 解析器,

- 根据ContentType请求头,选择不一样解析器对 请求体中的数据进行解析。 POST /index/ http1.1.\r\nhost:11.11.11.11\r\nContent-Type:url-formendo....

\r\n\r\nuser=alex&age=123
POST /index/ http1.1.\r\nhost:11.11.11.11\r\nContent-Type:application/json\r\n\r\n{....}

- 分页
- 对从数据库中获取到的数据进行分页处理: SQL -> limit offset

- 根据页码:http://www.luffycity.com/api/v1/student/?page=1&size=10
- 根据索引:http://www.luffycity.com/api/v1/student/?offset=60&limit=10 - 根据加密:http://www.luffycity.com/api/v1/student/?page=erd8

问题:为何页码越大速度越慢,以及如何解决? 缘由:页码越大向后须要扫描的行数越多,由于每次都是从0开始扫描。 解决:

- 限制显示的页数

- 记录当前页数据ID最大值和最小值,再次分页时,根据ID现行筛选,而后再分页。 - 序列化

- 对queryset序列化以及对请求数据格式校验。 - 渲染器

- 根据URL中传入的后缀,决定数据如何渲染到到页面上。 面试题:你写的视图类都继承过哪些类?

class View(object):
class APIView(View):
class GenericAPIView(views.APIView):
class GenericViewSet(ViewSetMixin, generics.GenericAPIView) class ModelViewSet(mixins.CreateModelMixin,

mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):

 

七、为何会出现跨域问题? 跨域是指从一个域名的网页去请求另外一个域名的资源。浏览器出于安全的考虑,不容许不一样源

的请求;
由于浏览器收到同源策略的限制,当前域名的js只能读取同域下的窗口属性。 同源策略:不一样的域名, 不一样端口, 不一样的协议不容许共享资源,保障浏览器安全。

处理方法:
一、jsonp 跨域方法 同源策略会阻止ajax请求;不阻止具备src属性的标签,因此动态建立script标签便可。具体以下:

咱们提供一个 script 标签。请求页面中的数据, 同时传入一个回调函数的名字。服务器端获得名字后,

拼接函数执行格式的字符串。发送回浏览器。script 在下载代码之后并执行, 执行的就是这个函数调 用形式的字符串,

所以就将本地函数调用了.同时拿到了从服务器端获得的数据。 二、CORS 跨域

CORS 是在 es5 以后提出的跨域方案. 只须要在服务器配置一个跨域响应头接口

容许你的域名来获取个人数据 response['Access-Control-Allow-Origin'] = "*"

容许你携带Content-Type请求头 response['Access-Control-Allow-Headers'] = "Content-Type"

容许你发送DELETE,PUT response['Access-Control-Allow-Methods'] = "DELETE,PUT"

CORS请求头的注意事项: - 简单请求

- 复杂请求
- 会发送两次请求

- 首先会发送options请求作预检
- 而后再发送真正的 PUT/POST....请求

只要同时知足如下两大条件,就属于简单请求。 (1) 请求方法是如下三种方法之一:

HEAD GET POST

(2)HTTP的头信息不超出如下几种字段: Accept

Accept-Language Content-Language

text/plain

 

Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、

非简单请求的CORS请求,会在正式通讯以前,增长一次HTTP(options)查询请 求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可使 用哪些HTTP动词和头信息字段。只有获得确定答复,

浏览器才会发出正式的XMLHttpRequest请求,不然就报错。

与jsonp相比的优势:
一、 JSONP只能实现GET请求,而CORS支持全部类型的HTTP请求。
二、 使用CORS,开发者可使用普通的XMLHttpRequest发起请求和得到数据,比起JSONP

有更好的错误处理。
三、 JSONP主要被老的浏览器支持,它们每每不支持CORS,而绝大多数现代浏览器都已经

支持了CORS。

八、面试题 (1)

var name = '景女神'

function Foo(name,age){ this.name = name;

this.age = age; this.getName = function(){

console.log(this.name); # 文州

(function(){
console.log(this.name); # 女神

})()

obj = new Foo('文州',19) obj.getName()

(2)
var name = '景女神'

function Foo(name,age){ this.name = name;

this.age = age; this.getName = function(){

console.log(this.name); # 文州 var that = this
(function(){

console.log(that.name); # 文州 })()

} }

} }

 

obj = new Foo('文州',19) obj.getName()

(3)
var name = '景女神' obj = {

name:'文州',
age: 19, getName:function(){

} }

console.log(this.name); # 文州 var that = this
(function(){

console.log(that.name); # 文州 })()

obj.getName()

九、你理解的Http协议? - 创建在tcp之上

- 一次请求一次响应而后断开链接(无状态、短链接) - 请求和响应
发送:请求头\r\n\r\n请求体

host:www.luffy.com\r\ncontent-type:application/json\r\n\r\n请求体 响应:响应头\r\n\r\n响应体

Http协议就是一个传输数据格式(官名是超文本传输协议)。 我以前在学习django框架的时候,是从socket服务端开始学起。 本身创造了一个socket服务器来充当:网站。 浏览器当socket客户端。

更清楚的明白到底http协议是什么?
- 请求头 请求体
- 响应头 响应体 一次请求响应后,断开链接(无状态,短链接)。

常见的请求头:
- Content-Type

原则上浏览器会根据Content-Type来决定显示返回的消息体内容的格

式。
- User-Agent
- referer, 来的,能够作图片防盗链。

告诉HTTP服务器,客户端使用的操做系统和浏览器的名称和版本 提供了Request的上下文信息的服务器,告诉服务器我是从哪一个连接过

- Host 请求报头域主要用于指定被请求资源的Internet主机和端口号,它一般 从HTTP URL中提取出来

 

- cookie

常见的状态码: -200
- 302

最重要的header,将cookie的值发送给HTTP服务器

请求成功 OK

重定向,新的URL会在response 中的Location中返回,浏览器将会自动使用新 的URL发出新的Request

- 304 - 400 - 403 - 404 - 500 - 503

表明上次的文档已经被缓存了, 还能够继续使用 客户端请求与语法错误,不能被服务器所理解 服务器收到请求,可是拒绝提供服务,好比没有找到cookie 请求资源不存在(输错了URL) 服务器发生了不可预期的错误 服务器当前不能处理客户端的请求,一段时间后可能恢复正常

常见的请求方法:
- GET/POST/DELETE/PUT/PATCH/OPTIONS

常见的请求体: Form表单提交:

POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\nusername=alex&password=123&... Ajax请求:

POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\nusername=alex&password=123&... POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\n{“username”:"alex","password":123}

补充:django中获取请求体 - request.POST

- request.body

十、中间件 定义:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插 件系统, 用于在全局范围内改变Django的输入和输出。每一个中间件组件都负责作一些特定的功能。 说的直白一点中间件是帮助咱们在视图函数执行以前和执行以后均可以作一些额外的操做, 它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些 方法。

内置的5个方法:
process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs) process_template_response(self,request,response) process_exception(self, request, exception) process_response(self, request, response)

使用中间件作过什么? - 内置

- csrf

 

- session - 自定义

- 登陆认证:再也不须要在每一个函数中添加装饰器
- 权限:当用户登陆时候获取当前用户全部权限并放入session,而后再次访问其余页 面,获取当前url并在session中 进行匹配。若是没有匹配成功,则在中间件返回“无权访问”

- 跨域,
- jsonp,动态建立一个script标签。
- cors,设置响应头 应用:本地开始先后端分离的时使用。

11. 如何实现的访问频率控制? 使用IP/用户帐号做为键,每次的登录时间戳做为值,构造一个字典形式的数据,存起来,每次登 陆时把时间戳列表的元素进行判断,把超时的删掉,再计算列表剩余的元素数就能作到频率限制了 匿名用户:使用IP控制,可是没法彻底控制,由于用户能够换代理IP 登陆用户:使用帐号控制,可是若是有不少帐号,也没法限制

十二、django组件:contenttype 组件的做用:能够经过两个字段让表和N张表建立FK关系

例如:
class Course(models.Model):
"""专题课程"""
name = models.CharField(max_length=128, unique=True) course_img = models.CharField(max_length=255)

# 不会在数据库生成列,只用于帮助你进行查询 policy_list = GenericRelation("PricePolicy")

class PricePolicy(models.Model):
"""价格与有课程效期表"""
content_type = models.ForeignKey(ContentType) # 关联course or degree_course object_id = models.PositiveIntegerField()

#不会在数据库生成列,只用于帮助你进行添加和查询 content_object = GenericForeignKey('content_type', 'object_id')

1三、原生Ajax:XMLHttpRequest对象: var xhr = new XMLHttpRequest() xhr.onreadystatechange = function(){

if(xhr.readyState == 4){
// 已经接收到所有响应数据,执行如下操做 var data = xhr.responseText;

console.log(data); }

 

};
xhr.open('POST', "/test/", true);

// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');

// 发送请求 xhr.send('n1=1;n2=2;');

1四、ORM相关

- only only()里的字段,表示只取相关字段的内容,注意:当only后进行for循环取值 时,若是取那些不在only括号内字段,会致使再次进行数据库查询,效率会差不少

和only相反,括号内的字段表示不取相关字段的内容
用于主动进行连表查询 FK时用,至关于主动作join(一次连表查询,连表查询

屡次单表操做,避免连表查询损耗;先查询想要的数据,而后构造条件,如:

- defer
- seleted_related
速度会相对慢点)
- prefetch_related id=[1,2,3],再次查询其余表根据id作条件。

- F - Q

用来更新获取原来值的功能,例如:Uinfo.objects.all().update(age=F("age")+1) 用于构造复杂的查询条件的,使用方法有对象方法和直接建立建立对象方法

Q功能详解: 数据库的查询条件咱们可使用filter,在filter里面的能够是两个条件他们之间是and的关

系,也能够是一个字典,例以下面的代码 models.Uinfo.objects.all().filter(id=1,name='李伟') conditon={

'id':'1',

'name':'李伟' }

models.Uinfo.objects.all().filter(**conditon)

除了上面的方法,咱们还能够加Q的对象,例如:
from django.db.models import Q models.Uinfo.objects.all().filter(Q(id=1))#条件是id为1的时候 models.Uinfo.objects.all().filter(Q(id=1)|Q(id__gt=3))#条件是或的关系 models.Uinfo.objects.all().filter(Q(id=1) & Q(id=4))# 条件是and的关系

Q的另一种用法
#q1 里面的条件都是or的关系

q1=Q()
q1.connector = 'OR' q1.children.append(('id',1)) q1.children.append(('id',3)) q1.children.append(('id',6))

#q2里面的条件都是or的关系

q2=Q()
q2.connector = 'OR' q2.children.append(('c',2)) q2.children.append(('c',4)) q2.children.append(('c',6))

 

#con 经过and的条件把q1和q2 联系到一块 con=Q()

con.add(q1,'AND') con.add(q2,'AND')

Q能把查询相互嵌套

- 经过ORM写偏原生SQL: - extra

Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params= (1,))
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])

Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by= ['-nid'])

- raw
# 执行原生SQL models.UserInfo.objects.raw('select * from userinfo')

# 若是SQL是其余表时,必须将名字设置为当前UserInfo对象的主键列名 models.UserInfo.objects.raw('select id as nid from 其余表')

# 为原生SQL设置参数
models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])

name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

- 原生SQL

from django.db import connection, connections
cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() # fetchall()/fetchmany(..)
PS: 选择数据库
queryset = models.Course.objects.using('default').all()

 

a. 需求: 只取某n列 queryset=[ {},{}]

models.User.objects.all().values( 'id','name')

queryset=[ (),()] models.User.objects.all().values_list( 'id','name')

queryset=[ obj,obj]
result = models.User.objects.all().only('id','name','age')
# result = models.User.objects.all().defer('id','name','age') for item in reuslt:
print(item.id,item.name,item.age)

b. 需求: 打印全部用户姓名以及部门名称

class depart: title = ....

class User:
name = ...
dp = FK(depart)
c.
select * from user
result = models.User.objects.all() for item in result: print(item.name)

select * from user left join depart on user.dp_id = depart.id result = models.User.objects.all().selected_related('dp')
for item in result:
print(item.name,item.dp.title )

注意:数据量比较大,不会使用FK,容许出现数据冗余,为了提升查询访问效率。

1五、支付宝支付相关 1.正式申请:须要营业执照 2.测试:沙箱测试环境 3.公钥私钥:支付宝的公钥和商家的私钥 4.加密方式:rsa

5.支付成功后,断电宕机无影响,支付宝会在24小时内发送信息让用户确认,只有用户确认后才算 是真正的成功
成功:return HttpResponse('success')
6.精度:小数点后两位

 

1六、git rebase的做用? 保持提交记录的整洁。

1七、使用git时,若是代码出现bug,大家是如何解决? 建立一个bug分支,而后进行bug处理,处理完毕后,合并到master分支。 删除bug分支
回到dev分支继续开发。

1八、redis是什么? 用于操做内存的软件。

数据存储模式有2种:cache-only,persistence; 一、cache-only即只作为“缓存”服务,不持久数据,数据在服务终止后将消失,此模式下也将 不存在“数据恢复”的手段,是一种安全性低/效率高/容易扩展的方式; 二、persistence即为内存中的数据持久备份到磁盘文件,在服务重启后能够恢复,此模式下数据 相对安全。

对于persistence持久化存储,Redis提供了两种持久化方法: Redis DataBase(简称RDB)

RDB是在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件 替换上次持久化的文件,达到数据恢复。 优势:使用单独子进程来进行持久化,主进程不会进行任何IO操做,保证了redis 的高性能 缺点:RDB是间隔一段时间进行持久化,若是持久化之间redis发生故障,会发生 数据丢失。因此这种方式更适合数据要求不严谨的时候

Append-only file (简称AOF)
Append-only file,将“操做 + 数据”以格式化指令的方式追加到操做日志文件的尾 部,在append操做返回后(已经写入到文件或者即将写入),才进行实际的数据变 更,“日志文件”保存了历史全部的操做过程;当server须要数据恢复时,能够直 接replay此日志文件,便可还原全部的操做过程。AOF相对可靠,它和mysql中 bin.log、apache.log、zookeeper中txn-log简直殊途同归。AOF文件内容是字符串,非 常容易阅读和解析。 优势:能够保持更高的数据完整性,若是设置追加file的时间是1s,若是redis发生 故障,最多会丢失1s的数据;且若是日志写入不完整支持redis-check-aof来进行日志 修复;AOF文件没被rewrite以前(文件过大时会对命令进行合并重写),能够删除 其中的某些命令(好比误操做的flushall)。 缺点:AOF文件比RDB文件大,且恢复速度慢。

- 至关因而大字典 - 单进程单线程
- 5大数据类型

字符串 列表 集合 字典

有序集合

 

redis的列表操做
- 左右操做,双向连接

- 阻塞
- 经过yield建立一个生成器完成一点一点获取(经过字典操做的源码来的灵感)

def list_iter(key,count=100): index = 0

while True:
data_list = conn.lrange('k1', index, index+count-1) if not data_list:

return index += count

for item in data_list: yield item

PS: 队列:先进先出 栈:后进先出

- 事务+一次发送多个命令:
conn = redis.Redis(host='47.94.172.250',port=6379,password='Luffy!4321')

pipe = conn.pipeline(transaction=True) pipe.multi()

pipe.set('k2','123') pipe.hset('k3','n1',666) pipe.lpush('k4','laonanhai')

pipe.execute()

1九、redis中使用链接池 本质,维护一个已经和服务端链接成功的socket。 之后再次发送数据时,直接获取一个socket,直接send数据。

20、解决数据库页数越大速度越慢。 - 限制页数

- 记录当前页最大ID、最小ID 错误答案:

- 扫描索引表
- 再去数据库表中获取数据

2一、作代码review 如何作代码review?

- 建立review分支:

谁来作代码review? - 组长

 

- 带你的人

2二、问题: 怎么在github上给别人修改代码? 一、fork

github上 不是有个fork么, 好,那么给别人的项目提交代码的方式就有了,先fork下别人的代 码,因而你的github上就出现了同名的项目,这个项目就属于你本身了,你把这个本身的项目 git clone到本地,修修改改,而后push到你本身的项目里;

二、pull request
在github上你的项目页面有个按钮,叫Pull request,对 你点它就会把你的修改发到对方的项目 里,人还会收到邮件呢,由原项目主人决定是否接受你的修改

2三、github不用反复输入用户名密码登陆 Https:

https://用户名:密码@github.com/WuPeiqi/dbhot.git
git remote add origin https://用户名:密码@github.com/WuPeiqi/dbhot.git

SSH:
git@github.com:WuPeiqi/dbhot.git

步骤:
一、大多数 Git 服务器都会选择使用 SSH 公钥来进行受权。系统中的每一个用户都必须提 供一个公钥用于受权,没有的话就要生成一个。生成公钥的过程在全部操做系统上都差 很少。 首先先确认一下是否已经有一个公钥了。SSH 公钥默认储存在帐户的主目录下的 ~/.ssh 目录。进去看看。
命令:cd ~/.ssh
二、关键是看有没有用 something 和 something.pub 来命名的一对文件,这个 something 通 常就是 id_dsa 或 id_rsa。有 .pub 后缀的文件就是公钥,另外一个文件则是密钥。假如没有 这些文件,或者干脆连 .ssh 目录都没有,能够用 ssh-keygen 来建立。该程序在 Linux/Mac 系统上由 SSH 包提供,而在 Windows 上则包含在 MSysGit 包里。 命令:ssh-keygen 三、它先要求你确认保存公钥的位置(.ssh/id_rsa),而后它会让你重复一个密码两次, 若是不想在使用公钥的时候输入密码,能够留空。 如今,全部作过这一步的用户都得把它们的公钥给你或者 Git 服务器的管理员(假设 SSH 服务被设定为使用公钥机制)。他们只须要复制 .pub 文件的内容而后发邮件给管理 员。
命令:cat ~/.ssh/id_rsa.pub
四、在GitHub上的我的中心的settings里的 SSH and GPG keys 中添加已生成的 SSH keys 即 可。

2四、 在django中应用redis:

1. 自定义使用redis import redis

2. 使用第三方组件
pip3 install django-redis

配置:
CACHES = {

 

"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} # "PASSWORD": "密码",
}

} }

使用:
conn = get_redis_connection("default")

2五、关于微信消息推送 网址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login 基于:已认证的微信服务号 主动推送微信消息。
前提:关注服务号
环境:沙箱环境

总结:

  1. 注册帐号

    appID:wx89085e915d351cae appsecret:64f87abfc664f1d4f11d0ac98b24c42d

    网页受权获取用户基本信息:47.98.134.86 或 域名

  2. 关注公众号(已认证的服务号)

  3. 生成二维码,用户扫描; 将用户信息发送给微信,微信再将数据发送给设置redirect_uri地址(md5值)

  4. 回调地址:47.98.134.86/callback/ - 受权

    - 用户md5
    - 获取wx_id

    在数据库中更新设置:wx_id

  5. 发送消息(模板消息)

    - wx_id
    - access_token(2小时有效期)

2六、互联网协议OSI四层、五层和七层模型

   四层:应用层、传输层、网络层和网络接口层
   五层:应用层、传输层、网络层、数据链路层和物理层
七层:应用层、表示层、会话层、传输层、网络层、数据链路层和物理层
  每层运行常见物理设备:
     传输层:四层交换机、四层路由器
     网络层:路由器和三层交换机
     数据链路层:网桥、以太网交换机、网卡
     物理层:中继器、集线器和双绞线

每层运行常见的协议: 传输层:TCP和UDP协议 网络层:IP协议 数据链路层:arp协议

2七、理解socket Socket是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口。在设计模式中,Socket其 实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面, 对用户来讲,一组简单的接口就是所有,让Socket去组织数据,以符合指定的协议。 其实socket就是一个模块。咱们经过调用模块中已经实现的方法创建两个进程之间的链接和通讯。 也有人将socket说成ip+port,由于ip是用来标识互联网中的一台主机的位置,而port是用来标识这台 机器上的一个应用程序。 因此咱们只要确立了ip和port就能找到一个应用程序,而且使用socket模块来与之通讯。

2八、理解TCP协议和UDP协议 TCP---传输控制协议,提供的是面向链接、可靠的字节流服务。当客户和服务器彼此交换数据前,必 须先在双方之间创建一个TCP链接,以后才能传输数据。TCP提供超时重发,丢弃重复数据,检验 数据,流量控制等功能,保证数据能从一端传到另外一端。 UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应 用程序传给IP层的数据报发送出去,可是并不能保证它们能到达目的地。因为UDP在传输数据报前 不用在客户和服务器之间创建一个链接,且没有超时重发等机制,故而传输速度很快。

2九、理解TCP协议中的三次握手和四次挥手 创建链接的三次握手

TCP是因特网中的传输层协议,使用三次握手协议创建链接。当主动方发出SYN链接请求后, 等待对方回答SYN+ACK[1],并最终对对方的 SYN 执行 ACK确认。这种创建链接的方法能够 防止产生错误的链接。[1]
TCP三次握手的过程以下:

客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。 服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入 SYN_RECV状态。 客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状 态。 三次握手完成,TCP客户端和服务器端成功地创建链接,能够开始传输数据了。

首先Client端发送链接请求报文,Server段接受链接后回复ACK报文,并为此次链接分配 资源。Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连 接就创建了。

 

断开链接的四次挥手: 假设Client端发起中断链接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我 Client端没有数据要发给你了",可是若是你还有数据没有发送完成,则没必要急着关闭Socket, 能够继续发送数据。因此你先发送ACK,"告诉Client端,你的请求我收到了,可是我还没准备 好,请继续你等个人消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN 报文。当Server端肯定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我 这边数据发完了,准备好关闭链接了"。Client端收到FIN报文后,"就知道能够关闭链接了,但 是他仍是不相信网络,怕Server端不知道要关闭,因此发送ACK后进入TIME_WAIT状态,如 果Server端没有收到ACK则能够重传。“,Server端收到ACK后,"就知道能够断开链接了"。 Client端等待了2MSL后依然没有收到回复,则证实Server端已正常关闭,那好,我Client端也可 以关闭链接了。Ok,TCP链接就这样关闭了!

30、TCP协议中为何链接的时候是三次握手,关闭的时候倒是四次握手? 由于当Server端收到Client端的SYN链接请求报文后,能够直接发送SYN+ACK报文。其中ACK报文 是用来应答的,SYN报文是用来同步的。可是关闭链接时,当Server端收到FIN报文时,极可能并不 会当即关闭SOCKET,因此只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。 只有等到我Server端全部的报文都发送完了,我才能发送FIN报文,所以不能一块儿发送。故须要四步 握手。

 

3一、TCP协议中在断开链接时,为何TIME_WAIT状态须要通过2MSL(最大报文段生存时 间)才能返回到CLOSE

状态? 虽然按道理,四个报文都发送完毕,咱们能够直接进入CLOSE状态了,可是咱们必须假象网络是不 可靠的,有能够最后一个ACK丢失。因此TIME_WAIT状态就是用来重发可能丢失的ACK报文。

3二、接口的幂等性?(是否会形成2次伤害) 一个接口经过1次相同的访问,再对该接口进行N次相同的访问时候,对资源不造影响,那么就认为 接口具备幂等性。

好比:
GET, 第一次获取结果、第二次也是获取结果对资源都不会形成影响,幂等。 POST,第一次新增数据,第二次也会再次新增,非幂等。
PUT, 第一次更新数据,第二次不会再次更新,幂等。 PATCH,第一次更新数据,第二次不会再次更新,非幂等。 DELTE,第一次删除数据,第二次不在再删除,幂等。

3三、Https和Http区别? 一、首先Https是Http的安全版,即HTTP下加入SSL层就是Https;

 

二、默认端口号不一样,Http是80端口,Https是443端口; 三、Http是超文本传输协议,信息是明文传输,能够自定义证书,在服务端建立一对证书,在客户 端必须携带证书;

Https是须要到ca申请证书(购买),在服务端建立一对证书,在客户端去机构获 取证书,数据加密后发给

   我们的服务单,而证书机构须要把公钥给改机构。

3四、路飞学城相关
1)购物车购买数量有限制吗? -- 有,防止有人恶意破坏,把大量商品加入购物车,不购买,占 用redis的负担
2)购物车是否设置超时时间? -- 能够设置,也能够不设置,其实只设置一下购物车购买数量即 可。 (.conn.expire("shopping_car_1_1", 60*30))
3)为何把购物车信息放入redis?

1.购物车的操做只是个临时状态,不须要放入数据库;

2.须要频繁对购物车进行修改,放入redis的话操做速度快。 4)为何要开发这个项目?

1.提升在线 教育的 完课率 (学成率) 2.项目的具体内容有:

        课程分两种,学位课和专题课
        购买课程时,能够选择不一样的价格策略来进行学习
        闯关式学习,对于学位课来讲,咱们不会一次性把所有课程的视频给学员,会进行闯关
        式学习,
             只有当当前阶段经过导师测试后,学员才有资格进行下一步的学习
       导师筛选,咱们对导师会有很严格的筛选,只有经过咱们的严格考核,才有资格作咱们
       的导师
       导师监督,人都有惰性心理,因此咱们会对咱们导师有严格的要求,导师必须对学员负
       责,天天都要有跟进记录,

无论是电话仍是QQ、微信,都要有记录上传系统,这些都会和他们的奖惩关 联

        导师答疑时间,不一样的课程,不一样的价位,会有不一样的答疑时间限制,在规定时间内,
        导师必须给学员进行回复
        报名时学员有权利选择导师,在学习期间,学员也有权利提出更换导师
        奖惩措施,对于导师来讲,每个导师带领一个学员时,咱们都会给导师帐户存入必定
        的奖金,直到学员毕业后才能提现,在学员学习期间,若是导师有不负责现象,咱们会
        作出相应的惩罚措施,作必定扣除奖金机制;对于学员来讲,学员可以按时或者提早在
        规定时间内学习完一个模块,做业和测试成绩优异的话,咱们会给必定的奖励。

5)这个项目的开发周期和团队构成 周期:初期开发到上线时间是大约四个月,以后一直在作网站的维护,bug的处理,开展一些 活动,广告之类的,

        还有一些小功能的开发
     团队构成:

开发
导师后台:stark组件和rbac 大约须要1人 管理后台:stark组件和rbac 大约须要1人

主站: vue.js

 

api接口 运维(1人)

测试(1人) 产品经理(1人) UI设计(1人) 运营(1人) 销售(5人) 全职导师(2人) 签约导师(。。。)

6)购买课程流程 加入购物车 去结算中心

去支付 7)路飞的主站业务

课程
课程列表

课程详细

     课程大纲、导师、推荐课程

价格策略

加入购物车

课程章节和课时

常见问题

评论

深科技 文章列表

     文章详细
     收藏
     点赞
     评论
     推荐其余优秀文章

支付
购物车

     结算中心
     当即支付
     知识点:

大约须要1人 2.5我的,组长偶尔会负责一些,不算是整我的力

redis
支付宝支付
微信消息推送 构建数据结构 优惠券+贝里+支付宝支付

我的中心

课程中心 8)播放视频:cc视频

加密 非加密

3五、Django、Flask和Tornado区别? Django:简单的说Django是一个大而全的Web框架,内置了不少组件,ORM、admin、Form、 ModelForm、中间件、信号和缓存等。

 

基于wsgi协议部署的,使用wsgiref模块实现此协议; Flask:微型的小而精的Web框架,可扩展性强,内置的组件不多,须要引入第三方组件实现功能业 务,若是开发简单的项目,

使用Flask比较快速和方便。若是开发大型项目,须要引入大量的第三方组件,这时Flask会越 来越像Django框架。基于wsgi协议部署,使用werkzeug模块实现此协议,模板系统由 Jinja2提 供。

Tornado:是一个轻量级的Web框架,可扩展性强,用于快速开发简单程序,用于强大的异步非阻塞 和内置WebSocket功能。

3六、Flask 10大基础知识 一、配置文件

Flask的配置文件全都放在 app.config 里,怎样修改配置文件呢? 首先在项目里建立一个 settings.py 文件,在文件里能够自定义修改配置文件,好比: class Config(object):

DEBUG = False
TESTING = False
DATABASE_URL = 'sqlite://:memory:'

class ProductionConfig(Config):
DATABASE_URL = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config): DEBUG = True

class TestingConfig(Config): TESTING = True

而后在 app.py 文件里引入自定义修改的配置文件 app.config.from_object("settings.DevelopmentConfig")
# 能够根据不一样的测试环境,引入不一样的配置文件
PS:内部的实现原理知识点 -- 获得一个字符串的路径 "settings.Foo" ,怎样找到类并获取其中 的大写的静态字段。

在 settings.py 文件里设置自定义的 Foo 类 静态属性必须是大写的,
class Foo:

DEBUG = True TEST = True

在 app.py 文件中引入

import importlib 持传递字符串来导入模块

 

path = "settings.Foo"

p,c = path.rsplit('.',maxsplit=1) m = importlib.import_module(p) cls = getattr(m,c)

# 若是找到这个类? for key in dir(cls):

if key.isupper(): print(key,getattr(cls,key))

二、路由系统 一般有3种定义路由函数的方法: 1.使用flask.Flask.route() 修饰器。 2.使用flask.Flask.add_url_rule()函数。

def index():
return 'index'

app.add_url_rule('/index', None, index)

三、视图

# 提供Pythonimport语法和(__import__()函数)的实现,提供支

# 至关于实现了 # 至关于实现了

import settings settings.Foo

-- 第一个参数是 url 路由,第二个参数是 endpoint

,第三个参数是 函数名 3.直接访问基于werkzeug路由系统的flask.Flask.url_map。 最经常使用的@app.route()装饰器

可以加参数:
参数一,url @app.route("/index") -- url 没有参数时

@app.route("/index/<int:nid>") -- url 有参数时,"<>" 这个是格式,int 是 定义参数类型

参数二,methods 默认的是 GET 请求 @app.route("/index/<int:nid>", methods= ['GET','POST'])
参数三,endpoint 定义 url 别名,用于反向生成 url ,不写时默认的是被装饰的函数名

@app.route("/index/<int:nid>", methods=['GET','POST'],endpoint='index') 反向解析时,须要引入 url_for ,使用: url_for('endpoint') 或者 url_for('index',nid=555)

参数: rule,

view_func, endpoint=None, methods=None, strict_slashes=None, redirect_to=None,

defaults=None, {'k':'v'}为函数提供参数

URL规则
视图函数名称 名称,用于反向生成URL,即: url_for('名称')

容许的请求方式,如:["GET","POST"] 对URL最后的 / 符号是否严格要求,

重定向到指定地址 默认值,当URL中无参数,函数须要参数时,使用defaults=

subdomain=None,

子域名访问

CBV
import functools

 

from flask import Flask,views app = Flask(__name__)

def wrapper(func): @functools.wraps(func) def inner(*args,**kwargs):

return func(*args,**kwargs) return inner

class UserView(views.MethodView): methods = ['GET']

decorators = [wrapper,]

def get(self,*args,**kwargs): return 'GET'

def post(self,*args,**kwargs): return 'POST'

app.add_url_rule('/user',None,UserView.as_view('uuuu'))

if __name__ == '__main__': app.run()

自定义路由匹配正则:
from flask import Flask,url_for

app = Flask(__name__)

# 步骤一:定制类
from werkzeug.routing import BaseConverter class RegexConverter(BaseConverter):

""" 自定义URL匹配正则表达式 """

def __init__(self, map, regex): super(RegexConverter, self).__init__(map) self.regex = regex

def to_python(self, value): """

路由匹配时,匹配成功后传递给视图函数中参数的值
:param value: :return:
"""
return int(value)

 

def to_url(self, value): """

使用url_for反向生成URL时,传递的参数通过该方法处理,返回的值用于 生成URL中的参数

:param value: :return:

"""
val = super(RegexConverter, self).to_url(value) return val

# 步骤二:添加到转换器 app.url_map.converters['reg'] = RegexConverter

"""
1. 用户发送请求
2. flask内部进行正则匹配
3. 调用to_python(正则匹配的结果)方法
4. to_python方法的返回值会交给视图函数的参数

"""

# 步骤三:使用自定义正则 @app.route('/index/<reg("\d+"):nid>') def index(nid):

print(nid,type(nid))

print(url_for('index',nid=987)) return "index"

if __name__ == '__main__': app.run()

四、请求相关 请求相关信息

request.method request.args request.form request.values request.cookies request.headers request.path request.full_path

request.script_root request.url request.base_url request.url_root request.host_url request.host request.files

 

obj = request.files['the_file_name'] obj.save('/var/www/uploads/' + secure_filename(f.filename))

五、响应 响应体:

1.return "asdfgh" -- 直接返回字符串
2.return jsonify({'k1':'v1'}) -- 返回序列化后的字符串
3.return render_template('index.html') -- 返回一个页面
4.return redirect('www.baidu.com') -- 重定向
定制响应头:
obj = make_response('kkk')
obj.headers['hhhhh'] = '555'
obj.set_cookie('key', 'value')
return obj -- 返回Response对象,make_response()函数能够接受1个,2个或3个参数

   问题:怎样实现登录验证功能
   方法一:

@app.route('/index') def index():

if not session.get('user'):
return redirect(url_for('login'))

return render_template('index.html')
session.get('user') 判断,这个方法显得很麻烦,不用

方法二:
import functools

def auth(func): @functools.wraps(func)

def inner(*args,**kwargs):
if not session.get('user'):

return redirect(url_for('login')) ret = func(*args,**kwargs)
return ret

return inner

@app.route('/index') @auth
def index():

return render_template('index.html',stu_dic=STUDENT_DICT)

# 在每一个须要验证的函数里都加上

把验证逻辑放在装饰器里,对每个须要验证的函数进行装饰 应用场景:比较少的函数中须要额外添加功能。

版本三:before_request @app.before_request

def auth():
if request.path == '/login':

return None

if session.get('user'): return None

return redirect('/login')

六、模板渲染
基本数据类型:能够执行python语法,如:dict.get() list[0],也可使用django模板语言的语 法,如:dict.name
传入函数

django 能够后面不加括号,函数自动执行

flask 不会自动执行,和python的语法同样,须要在函数名的后面加上括号才能执行 全局定义函数

@app.template_global() def sb(a1, a2):

# {{sb(1,9)}} return a1 + a2

@app.template_filter() def db(a1, a2, a3):

# {{ 1|db(2,3) }} return a1 + a2 + a3

模板继承:和 django 的模板继承同样

安全过滤器 前端:{{u|safe}}

后端:MarkUp('asdfg')


{% macro info(name, type='text', value='') %}

<h1>宏</h1>
<input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" value="提交">

{% endmacro %} {{ info('n1') }} {{ info('n2') }}

一个宏能够被不一样的模板使用,咱们能够声明在一个单独的模板文件中,导入的方法是 {% from 'form.html' import info %}
而后就能够在这个html文件中直接使用这个宏函数了

 

七、session
flask:当请求刚到来时,flask读取 cookie 中 session 对应的值,将该值解密并反序列化成字 典,放入内存以便视图函数使用。
视图函数:

@app.route('/ses') def ses():

session['k1'] = 123 session['k2'] = 456 del session['k1']

return "Session"

session['xxx'] = 123 session['xxx']

当请求结束时,flask 会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。

八、flash -- 闪现,在 session 中存储一个数据,读取时经过 pop 将数据移除。 from flask import Flask,flash,get_flashed_messages
@app.route('/page1')
def page1():

flash('临时数据存储','error') flash('sdfsdf234234','error') flash('adasdfasdf','info')

return "Session"

@app.route('/page2') def page2():

print(get_flashed_messages(category_filter=['error'])) return "Session"

九、中间件 __call__方法何时触发?

用户发起请求时,才执行 任务:在执行call方法以前,作一个操做,call方法执行以后作一个操做。 class Middleware(object):

def __init__(self,old): self.old = old

def __call__(self, *args, **kwargs):

ret = self.old(*args, **kwargs) return ret

 

if __name__ == '__main__':
app.wsgi_app = Middleware(app.wsgi_app) app.run()

十、特殊的装饰器 1.before_request

2.after_request 示例:

from flask import Flask app = Flask(__name__)

@app.before_request def x1():

print('before:x1') return '滚'

@app.before_request def xx1():

print('before:xx1')

@app.after_request def x2(response):

print('after:x2') return response

@app.after_request def xx2(response):

print('after:xx2') return response

@app.route('/index') def index():

print('index') return "Index"

@app.route('/order') def order():

print('order') return "order"

if __name__ == '__main__': app.run()

 

3. before_first_request

from flask import Flask app = Flask(__name__)

@app.before_first_request def x1():

print('123123')

@app.route('/index') def index():

print('index') return "Index"

@app.route('/order') def order():

print('order') return "order"

if __name__ == '__main__': app.run()

4. template_global 5. template_filter 6. errorhandler

@app.errorhandler(404) def not_found(arg):

print(arg)
return "没找到"

3七、Flask之蓝图 目标:给开发者提供目录结构 其余:

自定义模板、静态文件等 某一类 url 添加前缀

-- 在注册蓝图的时候能够给 url 添加前缀 app.register_blueprint(us, url_prefix='/api')

给一类 url 添加装饰器(例如: before_request)

3八、threading.local 做用:为每一个线程建立一个独立的空间,使得线程对本身的空间中的数据进行操做(数据隔离)。 应用:DBUtils 中为每一个线程建立一个数据库链接,注意:Flask中并无使用 threading.local ,而是 使用了 LocalStack ,细化到了协程。
import threading
from threading import local
import time

 

obj = local()

def task(i): obj.num = i

obj.sleep(2) print(obj.num, i)

for i in range(10):
t = threading.Thread(target = task, args = (i,)) t.start()

问题:如何获取一个线程的惟一标记?threading.get_ident() 根据字典自定义一个相似于 threading.local功能?

import time import threading

DIC = {}

def task(i):
ident = threading.get_ident() if ident in DIC :

DIC[ident]['num'] = i else:

DIC[ident] = {'num': i } time.sleep(2)

print(DIC[ident]['num'], i) for i in range(10):

t = threading.Thread(target = task, arg = (i,)) t.start()

根据字典自定义一个为每一个协程开辟空间进行存取数据 import time

import threading import greenlet

DIC = {} def task(i):

# ident = threading.get_ident() ident = greenlet.getcurrent()
if ident in DIC: DIC[ident]['xxxxx'] = i

 

else:
DIC[ident] = {'xxxxx':i } time.sleep(2)

print(DIC[ident]['xxxxx'],i)

for i in range(10):
t = threading.Thread(target=task,args=(i,))

t.start()

经过 getattr / setattr 构造出来 threading.local 的增强版(协程) imort time

import treading import greenlet try:

get_ident = greenlet.getcurrent except Exception as e:

get_ident = threading.get_ident class Local(object):

DIC = {}
def __getattr__(self, item):

ident = get_ident() if ident in self.DIC:

self.DIC[ident][key] = value else:

self.DIC[ident] = {key:value}

obj = Local()

def task(i): obj.xxxxx = i

time.sleep(2) print(obj.xxxxx,i)

for i in range(10):
t = threading.Thread(target=task,args=(i,) t.start()

3九、Flask的上下文管理
请求到来的时候:
# ctx = RequestContext(self, environ) # self是app对象,environ请求相关的原始数据

# ctx.request = Request(environ) # ctx.session = None

# 将包含了request/session的ctx对象放到“空调” {

 

1232:{ctx:ctx对象} 1231:{ctx:ctx对象} 1211:{ctx:ctx对象} 1111:{ctx:ctx对象} 1261:{ctx:ctx对象}

}

视图函数:
from flask import reuqest,session

request.method

  请求结束:
      根据当前线程的惟一标记,将“空调”上的数据移除。

40、Flask之偏函数 偏函数是从Python2.5引入的一个概念,经过functools模块被用户调用。偏函数是将所要承载的函数做为 partial()函数的第一个参数,原函数的各个参数依次做为partial()函数后续的参数,除非使用关键字参数。 偏函数能够帮助开发者自动传递参数。
例如:

from functools import partial def func(x, y, z):

return x + y + z new_func = partial(func, 10)

print(func(10, 10, 10)) # 30

print(new_func(10, 10)) # 30
应用场景:在Flask的源码里遇过:
请求进来触发 def __call__() 方法 -- > def wsgi_app() --> ctx.push() --> def push() -- > _request_ctx_stack.push(self) --> globals.py文件里 有关于偏函数的使用

request = LocalProxy(partial(_lookup_req_object, 'request')) session = LocalProxy(partial(_lookup_req_object, 'session')) g = LocalProxy(partial(_lookup_app_object, 'g'))

PS:
其实能够看到无论request仍是session最后都是经过getattr(top, name)获取的,也就是说确定有一个上下

文对象同时保持request和session。咱们只要一处导入request,在任何视图函数中均可以使用request,关键 是每次的都是不一样的request对象,说明获取request对象确定是一个动态的操做,否则确定都是相同的 request。这里的魔法就是_lookup_req_object函数和LocalProxy组合完成的。 LocalProxy是werkzeug.local.py中 定义的一个代理对象,它的做用就是将全部的请求都发给内部的_local对象。

当咱们调用request.method时会调用_lookup_req_object,对request的任何调用都是对 _lookup_req_object返回对象的调用。既然每次request都不一样,要么调用top = _request_ctx_stack.top返回的 top不一样,要么top.request属性不一样,在flask中每次返回的top是不同的,因此request的各个属性都是变化 的。

如今须要看看_request_ctx_stack = LocalStack(),LocalStack其实就是简单的模拟了堆栈的基本操做, push,top,pop,内部保存的线程本地变量是在多线程中request不混乱的关键。
4一、面向对象中的 super 方法的用途

 

1、根据 mro 的顺序执行方法

2、主动执行Base类的方法 4二、基于列表实现栈

class Stack(object): def __init__(self):

self.data = []

def push(self,val): self.data.append(val)

def pop(self):
return self.data.pop()

def top(self):
return self.data[-1]

_stack = Stack()

_stack.push('哈哈') _stack.push('呵呵')

print(_stack.pop())

print(_stack.pop()) 4三、在类中什么是函数,什么是方法?

class Foo(object):

def func(self): pass

# 执行方式一 obj = Foo() obj.func() # 方法

# 执行方式二

Foo.func(123) # 函数 4四、面向对象中双下划线方法

__str__ __init__ __repr__ __new__

__getattr__ __setattr__ __delattr__

单例模型用到

rest framework 序列化的时候用到了

在 flask Local对象用到
__call__ 在 Flask 的源码请求入口和 Django 的请求入口(WSGIHandler.__call__)都用到了

 

setitem
getitem delitem,
class Foo(object):

def __getitem__(self, item): return 1

def __setitem__(self, key, value): pass

def __delitem__(self, key): pass

obj = Foo() obj['k1'] obj['k1'] = 123 del obj['k1']

dict,api封装返回数据时:BaseResponse mro, 显示继承顺序 slots,Local对象,显示类中能调用的方法

4五、请求上下文管理(ctx):request,session
- 请求到来以后wsgi会触发__call__方法,由__call__方法再次调用wsgi_app方法 - 在wsgi_app方法中:
- 首先将 请求相关+空session 封装到一个RequestContext对象中,即:ctx。
- 将ctx交给LocalStack对象,再由LocalStack将ctx添加到Local中,Local结构: __storage__ = {

1231:{stack:[ctx,] } }

- 根据请求中的cookie中提取名称为sessionid对应的值,对cookie进行加密+反序列化,再次赋值给ctx 中的session

-> 视图函数

- 把session中的数据再次写入到cookie中。 - 将ctx删除

- 结果返回给用户浏览器 - 断开socket链接

4六、关于Flask中的g
g对象是application context,能够存储任何你想存储的内容,如数据库链接或登陆的用户。应用

上下文flask._app_ctx_stack 和 flask.g 差很少, 能够保存一些特定的数据到这两个对象内部, 固然这些数 据只在"一个请求"的生命周期中有效. 不过flask._app_ctx_stack 推荐给extension的开发者使用, flask.g

留给web 开发使用. 若是要"跨请求"来共享数据, 须要使用 session 对象.可使用get()方法来获取g的属 性,如:
user=getattr(flask.g,'user',None)
user=flask.g.get('user',None)

 

g 的生命周期:
g 是面向单个 request 的,一个 request 处理完,g 里的东西就没啦。(注意,这里说的 request

不是指 request context,从 0.10 版本开始,g 已是面向 app context 了。这里写面向单个 request 是为了帮助提问者理解问题中提到的区别,仅考虑在 web 下的场景。)
g 和 session 的比较:

session 是能够跨 request 使用的,session 的数据是通过加密后存储在 cookie 里的,用户每次 request 都会把这些 cookie 信息发回来,从而实现跨 request 使用。
g是面向单个 request 的,一个 request 处理完,g 里的东西就没啦。(注意,这里说的 request

不是指 request context,从 0.10 版本开始,g 已是面向 app context 了。这里写面向单个 request是为 了帮助提问者理解问题中提到的区别,仅考虑在 web 下的场景。)
g 和全局变量的比较:

全局变量在项目启动后就会引进,并且全局变量不会改变,不会消失;g 是在有请求的时候才

被设置,一次请求结束后会自动消失。 4七、什么是响应式布局?

简而言之,就是一个网站可以兼容多个终端--而不是为每一个终端作一个特定的版本。这个概念是为 解决移动互联网浏览而诞生的。 响应式布局能够为不一样终端的用户提供更加温馨的界面和更好的用户体验,并且随着目前大屏幕移 动设备的普及,用"大势所趋"来形容也不为过。随着愈来愈多的设计师采用这个技术,咱们不只看 到不少的创新,还看到了一些成形的模式。

优势:
面对不一样分辨率设备灵活性强
可以快捷解决多设备显示适应问题
缺点:
兼容各类设备工做量大,效率低下 代码累赘,会出现隐藏无用的元素,加载时间加长 其实这是一种折中性质的设计解决方案,多方面因素影响而达不到最佳效果 必定程度上改变了网站原有的布局结构,会出现用户混淆的状况 原理:使用了媒介查询:@media属性

4八、MySQL 数据库的引擎 1.Innodb引擎

支持事务 支持锁

行锁和表锁:可是当SQL语句没有指定要锁定的具体行范围的话,Innodb 也会锁全表。 支持外键约束

2.MyIASM引擎 MyIASM是MySQL默认的引擎,不支持事务,也不支持行级锁和外键,只支持表级锁。

两种引擎的比较: 大尺寸的数据集趋向于选择InnoDB引擎,由于它支持事务处理和故障恢复。数据库的大小决 定了故障恢复的时间长短,InnoDB能够利用事务日志进行数据恢复,这会比较快。主键查询 在InnoDB引擎下也会至关快,不过须要注意的是若是主键太长也会致使性能问题。大批的 INSERT语句(在每一个INSERT语句中写入多行,批量插入)在MyISAM下会快一些,可是 UPDATE语句在InnoDB下则会更快一些,尤为是在并发量大的时候。

4九、Flask 上下文管理

LocalProxy:它是werkzeug.local.py中定义的一个代理对象,它的做用就是将全部的请求都发给内部 的_local对象。
主要包含两种:

 

请求上下文(ctx = RequestContext())里面含有两种信息 request \ session app 上下文(app_ctx = AppContext())里面含有两种信息 app \ g 详细流程:
一、程序启动后:

启动项目的全局变量,实例化了两个对象,并建立了两个Stack 两个Local:

local1 = { }
local2 = { }

两个LocalStack: _request_ctx_stack _app_ctx_stack

二、请求到来后 对数据进行封装:

ctx = RequestContext(request,session)

app_ctx = AppContext(app,g) 保存数据:

将包含了(app,g)数据的app_ctx对象,利用 _app_ctx_stack(贝贝,LocalStack())将 app_ctx添加到Local中

storage = { 1231:{stack:[app_ctx(app,g),]}

} 将包含了request,session数据的ctx对象,利用_request_ctx_stack(刘淞,

LocalStack()),将ctx添加到Local中 storage = {

1231:{stack:[ctx(request,session),]} }

问题: Local是什么?做用?

答:存储数据,在Flask中给每个协程开辟一个内存空间,保证数据之间的隔离 LocalStack是什么?做用?

答:将Local的数据,字典storage对应的值维护成一个栈(栈里面有 push 和 pop 这两 个方法),而后把数据存储到Local 中

三、视图函数处理:
from flask import Flask,request,session,current_app,g

索引

 

id name pwd email
数据表中有上面4个字段,若是把 name pwd email 设成联合索引,只有下面的状况能命中

select * from tb where name='x'
select * from tb where name='x' and pwd='123'
select * from tb where name='x' and email='123@qq.com' select * from tb where name='x' and pwd='123' and email='xs' 当下面两种状况的时候不会命中索引
select * from tb where pwd='123'

app = Flask(__name__)

@app.route('/index') def index():

# 去请求上下文中获取值 _request_ctx_stack request.method # 找小东北获取值 session['xxx'] # 找龙泰获取值

# 去app上下文中获取值:_app_ctx_stack print(current_app)
print(g)

return "Index"

if __name__ == '__main__': app.run()

app.wsgi_app

经过LocalProxy对象+偏函数,调用LocalStack去Local中获取响应ctx、app_ctx中封装的 值。
问题:
为何要把 ctx=requestssion app_ctx = app/g ? 答:由于离线脚本须要使用app_ctx。

四、请求结束 _app_ctx_stack.pop()

_request_ctx_stack.pop() 50、MySQL 数据库的索引

索引做用:加速查找+约束。 索引种类:

- 主键索引:加速查找、不重复、非空 - 惟一索引:加速查找、不重复
- 普通索引:加速查找
- 联合索引:加速查找

- 联合惟一索引:加速查找、不重复 PS:联合索引遵循最左前缀原则。

select * from tb where pwd='123' and email='123@qq.com'

名词:
- 覆盖索引:在索引文件中就能够把想要的数据获得。

 

MySQL能够利用索引返回select列表中的字段,而没必要根据索引再次读取数据 文件,包函全部知足查询须要的数据的索引称为覆盖索引。 注意:若是使用覆盖索引,必定要注意select列表中只取出须要的列,不可 select * ,由于若是将全部字段一块儿作索引会致使索引文件过大,查询性能下 降。

select name from tb1;
- 索引合并:使用多个单列索引去查找数据。

一、索引合并是把几个索引的范围扫描合并成一个索引。

二、索引合并的时候,会对索引进行并集,交集或者先交集再并集操做,以便合并 成一个索引。

三、这些须要合并的索引只能是一个表的。不能对多表进行索引合并。

建立索引,但没法命中索引: https://www.cnblogs.com/wupeiqi/articles/5716963.html

5一、MySQL 数据库受权
MySQL 赋予用户权限命令的简单格式可归纳为: grant 权限 on 数据库对象 to 用户 详解:https://www.cnblogs.com/bethal/p/5512755.html

5二、MySQL 数据库视图 (View)是一种虚拟存在的表。其内容与真实的表类似,包含一系列带有名称的列和行数据。

可是视图并不在数据库中以存储的数据的形式存在。行和列的数据来自定义视图时查询所引用的基 本表,而且在具体引用视图时动态生成。
视图是存储在数据库中的查询的SQL 语句,它主要出于两种缘由:安全缘由, 视图能够隐藏一些 数据,如:社会保险基金表,能够用视图只显示姓名,地址,而不显示社会保险号和工资数等,另 一缘由是可以使复杂的查询易于理解和使用。

:

12.12....; MySQL 数据库触发器

CREATE TRIGGER trigger_name trigger_time
trigger_event ON tbl_name
FOR EACH ROW

trigger_stmt

weiv etaerc图视建创

图视

和查看数据库(show databases;)查看表格(show tables;)同样,查看触发器的语法如

 

下:

SHOW TRIGGERS[FROM schema_name]; 和删除数据库、删除表格同样,删除触发器的语法以下:

DROPTRIGGER[IF EXISTS][schema_name.]trigger_name 触发器的执行顺序

咱们创建的数据库通常都是 InnoDB 数据库,其上创建的表是事务性表,也就是事务安全的。这 时,若SQL语句或触发器执行失败,MySQL 会回滚事务,有:

1若是 BEFORE 触发器执行失败,SQL 没法正确执行。 2SQL 执行失败时,AFTER 型触发器不会触发。

3AFTER 类型的触发器执行失败,SQL 会回滚。

5四、MySQL 数据库之函数 对数据中的值进行操做

MySQL数据库提供了不少函数包括:

   数学函数;
   字符串函数;
   日期和时间函数;
   条件判断函数;
   系统信息函数;
   加密函数;
   格式化函数;

具体参考:https://www.cnblogs.com/kissdodog/p/4168721.html 5五、MySQL 数据库之存储过程

存储过程简介
SQL语句须要先编译而后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的 SQL语句集,经编译后存储在数据库中,用户经过指定存储过程的名字并给定参数(若是该 存储过程带有参数)来调用执行它。

存储过程是可编程的函数,在数据库中建立并保存,能够由SQL语句和控制结构组成。当想 要在不一样的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是很是有用 的。数据库中的存储过程能够看作是对编程中面向对象方法的模拟,它容许控制数据的访问 方式。

存储过程的优势:

(1).加强SQL语言的功能和灵活性:存储过程能够用控制语句编写,有很强的灵活性,能够完 成复杂的判断和较复杂的运算。

(2).标准组件式编程:存储过程被建立后,能够在程序中被屡次调用,而没必要从新编写该存储 过程的SQL语句。并且数据库专业人员能够随时对存储过程进行修改,对应用程序源代码毫 无影响。

,器发触除删

,器发触看查

(3).较快的执行速度:若是某一操做包含大量的Transaction-SQL代码或分别被屡次执行,那么 存储过程要比批处理的执行速度快不少。由于存储过程是预编译的。在首次运行一个存储过 程时查询,优化器对其进行分析优化,而且给出最终被存储在系统表中的执行计划。而批处 理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。

 

(4).减小网络流量:针对同一个数据库对象的操做(如查询、修改),若是这一操做所涉及的 Transaction-SQL语句被组织进存储过程,那么当在客户计算机上调用该存储过程时,网络中传 送的只是该调用语句,从而大大减小网络流量并下降了网络负载。

(5).做为一种安全机制来充分利用:经过对执行某一存储过程的权限进行限制,可以实现对相 应的数据的访问权限的限制,避免了非受权用户对数据的访问,保证了数据的安全。

     对结果集合返回值进行复杂操做。

DELIMITER //
CREATE PROCEDURE myproc(OUT s int) BEGIN
SELECT COUNT(*) INTO s FROM students; END
//
DELIMITER ;

具体可参考:https://www.cnblogs.com/mark-chan/p/5384139.html 5六、Flask 中的组件有哪些?

一、flask-session 二、DBUtils 三、wtforms 四、sqlalchemy 五、flask-script 六、flask-migrate

数据库链接池

a. 增长 runserver

b. 位置传参

c.关键字传参

5七、使用装饰器,如何不改变函数签名
给装饰器的内层函数加上装饰器 functools.wraps(func) ,会保留原函数的元信息,书写形式例如: def wrapper(func):

@functools.wraps(func) def inner(*args,**kwargs):

return func(*args,**kwargs) return inner

5八、类的私有化 通常状况下,类的私有化对象是不能调用的,若是想调用,就要写成这种形式的 class Foo(object):

def __init__(self, name, age): self.name = name self.__age = age

体程过 ]... 性特[ )]]...型类据数 名数 参 ]TUONI|TUO|NI[,[型类据数 名数参 ]TUONI|TUO|NI[[(名程过 ERUDECORP ETAERC

法语 建创的程过储存LQSyM

def func(self): print(self.__age)

 

obj = Foo('oldboy', 50) print(obj.name) print(obj._Foo__age) obj.func()

# 必定能使用

# 对象调用类的私有属性的方法

注意:私有化,在子类父类之间是不能互相调用的