知识点备忘
一、Django的中间件的整理
1、Django的中间件是什么?
答:Django的中间件就是一个类,是介于请求和响应之间的一道处理过程,相对比较轻量级,并且在全局上改变Django的输入和输出。
2、中间价的几个方法?
答:中间件一共有五个方法
process_request(self,request)
process_view(self, request, callback, callback_args, callback_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)
3、中间件的执行流程?
当用户请求的时候会依次经过所有的中间件,这个时候请求的是所有process_request,当最后一个process_request到达路由关系映射之后,返回到中间件的response_view, 到达视图函数中,视图函数处理后,如果有模板渲染,执行process_template_response,如果在以上执行的过程中出错了,执行process_exception,最后通过process_response返回给请求者。如下图所示
注意:
1、process_request一般不要有返回值,如果有返回值后续视图函数就不会执行了,会执行自己的response和process_response;process_response中必须要有返回值。
2、process_view如果有返回值,会越过其他process_view,但是所有的process_response还是会执行
4、中间件的应用?
当批量做一些操作的时候可以使用中间件
当有几个函数要做批量处理的时候可以使用装饰器的方法
比如:
登录认证
权限
CORS跨域(由于好多的请求都可能存在跨域问题,所以直接写一个中间件,就不用每次都在响应的时候设置响应头了)
csrf (执行process_view,在这view里面去拿csrf_token,在看有没有加特别的装饰器,特殊的装饰器,如果那个函数不需要认证,则可以取设置一个特殊的装饰器)
session
缓存(请求进来,先去缓存获取,再往后执行)
2、cookie和session的工作原理?
cookie可以单独工作
cookie也可以和session配合来用
每一个浏览器都会有一个cookie:{}
浏览器第一次访问服务器的时候cookie是空的
服务器需要让客户端保存一些数据cookie
{"sessionID":"随机字符串"},当下次请求的时候就会带着一些你保存的数据
django_session表里的每一条记录就是一个个用户,类似一个大的字典
session_key:存的是sessionID对应的值
session_data:{"":"","":"",...}存的是一组组键值对
等再次访问的时候就会带着sessionID
补充:从输入url到页面加载发生了什么?
从总体来说分为以下几个过程:
1、 输入网址按enter建
2、 在发送http请求前,需要域名解析(DNS解析)
3、 浏览器向服务器发送TCP连接,与浏览器建立tcp三次握手
4、 握手成功后,浏览器向服务器发送HTTP请求,请求数据包。
5、 服务器处理收到的请求,将数据返回到浏览器,
6、 浏览器收到http响应,读取页面内容,浏览器渲染,解析html源码
7、 连接结束
三次握手的流程:
3、Django的请求生命周期?
答:请求一进来会先走wsgi(wsgiref和uwsgi),到达中间件-----路由----视图-----从数据库获取数据进行模板渲染。
4、路由
一旦匹配成功则不再继续
若要从url中获取一个值,只需要在他周围放置一对圆括号。
1、 有名分组和无名分组
在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern),其中name 是组的名称,pattern 是要匹配的模式
分发 include
如果url出现覆盖现象的情况下,匹配第一个url
2、 反向解析(不让url硬编码)
答:有两种方式
在视图中,通过reverse 反向解析,还可以加一个namespace的参数。Namespace:name
reverse('n1')
reverse('n2',args=(666,))
在模板中
{%
url 'n1' %}
{% url 'n2' 666 %}
3、在源码里面看到路由还可以以这样的方式返回 ([] ,None,namespace)。Stark组件就是这样实现的
5、视图
1、请求相关的一些常见的方法有哪些、?
Request.method #请求方法
Request.GET #GET 请求
Request.POST #POST 请求
Request.path #获取url路径,不包括参数
Request.get_full_path # 获取url路径,包括参数
Request.cookies
Request.FILEs
Request.user
Request.session
6、ORM
1、 什么是ORM
答:ORM是对象关系映射
数据库中的表名对应-------类名
字段 ------------------------ 属性
表记录-------------------------类实例化对象
ORM的两大功能
操作表
操作数据行
2、 谈谈你对QuerySet的理解,以及它有哪些方法?
答:Queryset可切片,可迭代,缓存 机制、惰性查询(不用不求)
Update, create , delete
2、13个API查询,另加两个
基于对象的查询
all, filter, get ,exclude , values , values_list , order_by , reverse , distanct ,count , first , last ,exits , only ,defer
all :打印的是一个QuerySet集合,一个列表里面放的对象
values:是一个字典的形式
values_list : 是一个元组的形式
基于双下划线的查询
Id__in
Id__lt #小于
Id__gt #大于
Name__contains #包括。。。
Name__icontains #包括。。。但是大小写不敏感
Id__range() #范围是在。。。between and
Startswith , isstartwith , endswith , iendswith
3、 render函数的功能?
返回一个页面
模板语法:将变量如何巧妙的嵌入到HTML页面中
Redirect :发送了第二次请求,url更新
Render : 只会返回页面内容,但是未发送第二次请求
7、模板
1、模板语法的目的是什么?
将变量如何巧妙的嵌入到HTML页面中
2、模板语法之变量 {{ }}
3、 模板语法之标签{% tag %}
创建的有
for 标签
for….empty (给出的组是空的或者没有找到时,可有所操作)
if 标签
{% csrf_token %}+
4、 模板语法之过滤器{{obj|filter_name:param }}
a)
Defaule:如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。
b) {{ value |length}} :返回值的长度。它对字符串和列表都起作用
c) {{ value|filesizeformat}} :将值格式化成我们人能看懂的文件尺寸
d) {{ vaue|date:’Y-m-d’}} : 转换时间格式
e) {{value |slice:”2:-1”}} :切片
f) {{ safe }} :确保你的数据是安全的,才被当做标签
8、 Form组件
1 ….Form组件可以做几件事情?
a) 用户请求数据验证
b) 自动生成错误信息
c) 打包用户提交的正确信息
d) 保留上次输入内容
e) 自动创建input标签并且可以设置样式
2、 Form组件的使用
写一个类
字段(参数)
- require
- max_length
- min_length
- error_message
- validate=[] #自定制的正则表达式
方法
- clean_字段名称
使用:
- GET请求实例化直接render回去
POST
实例化(request.POST)
is_valid()
clean_data
errors
注意:ChoiceField数据源时时更新
9、Ajax的特点:
异步交互:当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
局部刷新: 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
9、 csrf跨站请求的三种方式?
1、 自己组装一组键值对发过去
2、 自己设置头信息
3、 $.ajaxSetup({
10、 怎么上传文件?
有两种方式:
1、 Form表单上传文件。需要加一个enctype=’multipart/form-data’
2、 Ajax上传文件
利用FormData,既可以处理二进制,也可以处理字典,列表等
ajax,使用FormData的最大优点就是我们可以异步上传一个二进制文件.
要是使用FormData一定要加上:
一定要加上:
contentType:false
processDate:false #不做预处理
十三、Python基础
1、 为什么学Python?是什么时候开始接触Python的?15年接触Python
答:公司项目用Python
容易上手
Python火
(2) 学校社团有学习Python的,我那时候感兴趣,就报名了。在那里面成长了不少,一个组一个组的分配学习任务,每天一块讨论问题,学着学着感觉python语言比起java的语言简练了,就慢慢的自学、通过看网上的视频,看官方文档等。
2、说说你了解的PEP8 规范?
答
a、代码编排:缩进,4和空格的缩进;换行可以使用反斜杠
b、 文档排版:不要在一句import中导入多个类,比如import os ,sys不推荐这样。
c、 空格的使用:函数的左右括号前不要加空格,操作符左右各加一个空格;if /for /whilt 语句中,即使执行语句只有一句,也另起一行写
d、 注释:行注释:用# 块注释:用’’’ ’’’
e、 文档描述:一个功能写完可以写一个描述,让人一看就知道是干啥的
f、 命名规范:命名的时候避免使用关键字命名;首字母不能是数字开头,可以是字母数字下划线的组合;尽量命名的时候有功能性的命名。
2、简述一下函数式编程?
答:函数是编程是使用一系列的函数去接解决问题,会根据参数的不同产出不同的结果。除了匿名函数外,Python还是用filter,map,reduce函数来支持函数式编程
匿名函数:也就是lambda表达是,当一些简单的功能需要用函数去处理的时候就可以使用匿名函数
filter():包括两个参数,分别是function和list。根据function中返回值是否为True来过滤list参数中的项,最后返回结果。
map():两个参数,一个是函数名,一个是列表。将函数里面的处理结果以列表的形式返回
reduce():具体的做法如下:首先从序列中去除头两个元素并把它传递到那个二元函数中去,求出一个值,再把这个加到序列中循环求下一个值,直到最后一个值 。
reduce(lambda x,y:sum([x,y]),range(1,101)) #吧1传给了x,吧101传给了y,计算除了1-100的和
3、什么是匿名函数,匿名函数有什么局限性?
答:匿名函数,也就是lambda表达式,一些简单的功能需要用函数处理的时候可以使用匿名函数
匿名函数顾名思义就是函数没有名字,因此不用担心函数名冲突,
不过python对匿名函数的支持有限,只有一些简单的情况下可以使用匿名函数。
4、with语句、上下文管理
答:使用with后不管with中的代码出现什么错误,都会进行对当前的对象进行清理工作
原理:
上下文管理器就是在对象内部实现了两个方法:__enter__和__exit__()
__enter__方法会在with代码块执行之前执行
__exit__方法会在代码块执行结束后执行
5、函数装饰器有什么作用?
在不修改源代码的基础上,在函数执行之前或者执行之后添加的操作
6、简述Python的作用域以及Python搜索变量的顺序
Python的作用域简单的说也就是作用范围,
作用域分为两种:
全局作用域:在整个文件的任意位置都能被引用,全局有效(全局命名空间与内置命名空间的名字都属于全局范围)
局部作用域:局部命名空间,只能在局部范围内生效
Python搜索变量的顺序?
LEGB
首先找函数内部local,然后找函数内部的函数enclosing,其次找全局global,最后build-in找内置作用域。
为什么要有作用域?
为了函数内部的变量不影响到全局
7、什么是闭包函数?
答:内部的函数包含了对函数作用域中变量的引用而非全局作用域
判断是否是闭包的方法?__closure__
8、字符串常见的方法有哪些?
答:strip(), split() , startwiths() ,index() , endwiths() , replace , join,format,capitalize (首字母大写), upper() , Lower()
Index和find的区别?
Index找索引,找不到就会报错,
Find 找索引,找不到返回-1
9、列表常见方法?
增:append:添加一个元素到末尾,只能添加一个元素。可以添加一个列表
extend : 添加多个元素
insert(3,’age’) : 按照索引添加一个元素
删:remove ,pop ., clear ,del
Remove和pop的区别?
Remove(‘b’) #指定一个元素删除,如果元素不存在则报错,没有返回值
Pop()#根据索引删除一个元素,如果不传索引,默认从末尾删除一个值,有返回值
Clear 直接删除列表中的所有元素
Del 可以根据切片删除多个值
改:a[4] = ‘sdsdf’ 根据索引修改
查:a[3] 索引查看元素
a.index(‘a’) 查看一个元素的索引
a.count(‘a’) 查看a这个元素在这个列表中出现的次数
切片
a[1:3] 注意顾头不顾尾
例题:a = ["q","w","e","r","t","y"]
请通过切片打印出:['r', 'e'] 答:a[3:1:-1]
10、字典常见方法?
Get , pop , update ,copy , items , popitems . values , keys , 等
11、元组常见方法?
Count , index
12、集合常见方法?
add , clear , copy .,
|并集(print(pythons.union(linuxs)))
&交集(print(pythons.intersection(linuxs)))
-差集(print(pythons.difference(linuxs)))
^对称差集(print(pythons.symmetric_difference(linuxs)))
集合的元素遵循三个原则:
1、 每个元素都是不可变数据类型的
2、 没有重复的元素
3、 无序
13、Collections模块
a) 有序字典
b) 命名元组
c) 默认值字典
d) 双向队列 dequeue
14、unicode和utf-8的区别?
unicode:优点是字符转换数字的时候速度快,缺点是占用空间大
utf-8:优点是精准,可变长,转换速度慢,缺点是节省空间
【unicode:多的字符都是2bytes,优点是字符转换数字的时候速度快,缺点是占用空间大】
【utf-8:精准,可变长,优点是节省空间;缺点是转换速度慢,因为每次转换都需要计算出需要多长bytes才能准确表示】
15、Python2和Python3的区别?
答:我接触的他们的最大的区别是编码的不同
(1)Python2里面默认是ascII , python2中的字符串就是bytes,python2中的字符串前面加u,就是unicode
Python3里面默认的是unicode,python3中的字符串被识别为unicode,python3中的字符串 encede得到bytes
(2) python2中的字符串有str和unicode两种类型
Python3中的字符串有str和bytes两种类型
(3)Xrange()返回的是一个可迭代对象 和range()返回的是一个列表
(4)Python2中的文件读取Xreadlines 和 Python3中的readline、
16、Python的垃圾回收机制?
Python采用的是引用计数为主,标记-清除机制和分代计数两种机制为辅
引用计数:
Python中万物皆对象,他们的核心就是一个结构体:pyObject
当一个对象有新的引用时,他的引用计数就会增加,当一个对象被删除,他的引用计数就会减少。
当引用计数为0时,该对象的生命就结束了。
引用计数机制的优点:
1、 简单
2、 实时性:一旦没有引用,内存就直接释放了,不用像其他机制等到特定的时机
应用计数机制的缺点:
1、 维护引用计数消耗资源
2、 循环引用
标记-清除机制
基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发
遍历以对象为节点、以引用为边构成的图,吧所有可以访问到打上标记,然后清扫一遍内存空间,
吧所有没标记的对象释放。
分代技术
分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,
每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,
存活时间通常利用经过几次垃圾回收来度量。
Python默认定义了三代对象集合,索引数越大,对象存活时间越长。
17、什么是多道技术?
答:多道技术也就是多个程序
1、 时间上的复用:多个程序要让他们之间能切换
a) 什么时候要切?
i. 一个程序占用时间过长的时候要切
ii. 当CPU遇到IO阻塞的时候要切
2、 空间上的复用:内存要支持同时跑进多个程序
18、操作系统的两大作用
a) 为应用程序提供如何使用硬件资源的抽象
b) 把多个程序对硬件的竞争变得有序化(管理应用程序)
十一、面向对象
1、你对函数式编程和面向对象编程的理解?
答:从写代码的角度来说,
函数式编程是:将公共功能编写成一个函数,通过参数的不同来产出不同的结果
面向对象编程是:主要体现在三大特性:封装、继承、多态
多态:鸭子类型(只要能呱呱叫就是鸭子了),由于Python是非强类型的,例如传入的值不管是什么,只要有我自己想调用的方法就行了,本身就是多态的。
封装:
数据的封装
举例、:在构造 方法里面self.name ,self.age
方法和属性的封装:
举例:像是动物类,狗类,猫类等
继承:如果好多类有相同的方法和属性,为了减少代码的重用,就可以提取到基类中
在Python中是有多继承的,当前类中没有方法或者其他字段,去基类中查找。
派生类:谁继承谁就是派生类,也就是子类
广度优先:新式类
深度优先:经典类
经典类:在Python2中的继承没有继承object类的是经典类
新式类:在Python2中继承了object的是新式类
哦,还有一些比如特殊的带双下划线的方法和metaclass,后面研究了一下
特殊的方法有哪些呢?
__call__:单利用metaclass创建类的时候;用类做装饰器;Flask源码;restframework做自定义验证规则的时候
__new__:单利模式;自定义Form验证;wtforms源码;Django rest-framework中,序列化源码(实例化的时候,先执行__new__,再执行__init__)****;
__init__:构造方法
__del__析构方法 ,当对象在内存中被释放时,自动触发执行。析构函数的调用都是由解释器在进行垃圾回收时自动触发代码的执行
__iter__:一个对象for循环的时候,返回一个迭代器,生成器也是一个迭代器。stark组件中组合搜索的时候用到过*****
__getattr__:Flask源码,自定义本地线程的时候用过;djangorestframe中request中取值
__setattr__:
__getitem__:session源码 fun[‘qqq’]
__next__:
__dict__:取到类中的所有方法和属性。自定义Form组件的时候用到过
__add__:对象相加默认会执行__add__方法
data = obj1+obj2
#obj1.__add__(obj2)
减,成
__class__
__enter__
__exit__
__str__:改变对象的字符串显示
metaclass
- 流程:先执行元类的__init__方法
如果实例化一个对象先执行__call__方法
完了执行自己类的__new__方法和__init__方法
- wtforms源码
2、如何捕捉异常、常用的异常机制有哪些?
如果我们没有对异常进行任何预防,那么在程序执行过程中就会发生异常,就会终端程序,不会
继续执行后续代码,所以我们调用Python默认的异常处理器来捕捉异常。
异常处理的机制
其实通过if也是可以处理异常的,只不过如果逻辑特别多的时候,都使用if去处理异常,会使代码的可读性极差。所以还有一种机制
try….except…else….finally
try里面放的是被检测的代码块,except是try中一旦检测到异常,就执行except里面的代码,
else:如果出现问题了不会执行else里面的代码,如果都正确了就会执行else里面的代码。
Finally:不管这段代码有没有出错,都会执行的内容
Assert ……断言:判断assert后面紧跟的语句是True还是False。如果是True则继续执行后续代码,如果是False就会报错,
3、常见的异常有哪些/?
答:NameError 尝试访问一个没有声明的变量
ZeroDivisionError 除数为0
SyntaxError 语法错误
IndexError 索引超出了范围
KeyError 请求一个不存在的字典关键字
IOError 输入输出错误,比如你要读的文件不存在
AttributeError 尝试访问未知的对象属性
ValueError 传给函数的参数值类型不正确
4、经典类和新式类的区别?
Python2中有两种:
经典类:不继承object
新式类:继承object
多继承的时候查找顺序是不同的
经典类:深度优先
新式类:广度优先
Python3中只有新式类,,可以用__mro__方法查看类继承的顺序
5、面向对象的应用
Django的CBV模式
Rest framework
中间件
4、特殊方法:
__init__ :初始化一个类实例,第一个参数是self
__iter__
__new__ :在__init__执行之前,__new__方法是新建一个类实例,第一个参数是cls
__call__ :哪里用过,在rest framework 序列化在用户请求数据验证时,自定义验证规则、Django的请求入口:__call__方法
Flask 请求入口:也是执行__call__方法
Django中间件 执行的__call__方法,在__call__方法里面process_request,….
__setitem__:自定义session的时候用了。设置类成员
__iter__
__dict__
__class__
5、Metaclass: 指定当前类是由谁创建
Type 创建类,metaclass不写默认是由type创建的类
6、Python中的@property有什么作用?如何实现成员变量的只读属性?
g) @propery就是吧一个方法当做一个属性来用
h) 访问类或示例的属性是直接通过obj.xxx的形式访问,但property是一个特殊的属性,访问
添加了装饰器@property的方法无序额外的添加()来调用,而是以属性的方式来访问。所以
利用这个属性可以虚拟实现类属性的只读设置
7、 静态方法staticmethod和类方法classmethod?
a) 相同点:都可以用类名去调用,不需要实例化
b) 不同点:
i. 静态方法不需要传参数
ii. 类方法需要传一个cls参数,
8、 Instance和issubclass
Instance(obj,cls) :检查一个obj是不是这个类实例
Issubclass(sub,supper) :检查sub是不是super的子类
9、 什么是反射?
a) 可以用字符串的方式去访问对象的属性,调用对象的方法
十二、函数
1、*args,**kwargs是干什么用的?
*args和**kwargs称之是可变长参数,当函数需要传太多参数的时候可以用他们来代替
按照位置传参数冗余的部分,会被形参中的*保存成元组的形式赋值给arg。
按照关键字传参数冗余的部分,会被形参中的**保存成字典的形式赋值给kwargs
2、传参数的时候传的是引用还是值?
看是什么类型
不管是字符串,数字,还是列表都是传的引用,只不过最终现象不一样。可以 通过id查看一下
3、 什么是闭包?
答:内部函数包含对外部函数作用域(而非全局作用域)中变量的引用。
装饰器就是使用闭包的原理
4、 怎么理解深浅拷贝?
深拷贝deepcopy:会拷贝父对象及其子对象
浅拷贝copy.copy():只会拷贝父对象,不会拷贝子对象
比如,如果一个对象里面又包含了另外一个对象,浅拷贝的时候只是把外部对象拷贝了一份
如果是深拷贝,会把外部的拷贝,吧内部的也拷贝
在什么时候用到了拷贝?
Request.GET 是不一个QueryDict对象,是不可以修改的,需要加一个参数_mutable = True才可以修改,为了不影响其他的时候,我们可以拷贝一份,在做修改。
5、 编码问题
Python3中的字符串是unicode
Python2中的字符串是字节
6、 装饰器是什么?什么时候用过?
答:在不改变原有代码的基础上在执行之前或者执行之后做点操作
Flask的路由是用装饰器做的,flask的路由本质
用户认证的时候也用了装饰器,但是如果视图多的话可以用中间件的形式
装饰器的执行流程是什么样的?
答:
7、 谈谈你理解的函数式编程:
答:函数是编程是使用一系列的函数去接解决问题,会根据参数的不同产出不同的结果。除了匿名函数外,Python还是用filter,map,reduce函数来支持函数式编程
匿名函数:也就是lambda表达是,当一些简单的功能需要用函数去处理的时候就可以使用匿名函数
Filter():
Map():
Reduce():
8、 什么是可迭代对象?迭代器?生成器?
答:可迭代对象:含有__iter__的就是可迭代对象,返回一个迭代器
迭代器:含有__next__方法的就是迭代器,只能往前更新迭代,不能往后退。
生成器:基于函数+yield实现,即可以取值,也可以生成值,它也有一个__next__方法,具有迭代器的特性。返回一个生成器
你在哪里用过生成器?
答:在Crm中,获取返回的数据需如果不是自己想要的格式,可以进行二次加工,再在模板中循环展示时,可使用生成器减少循环。
9、 为什么要有作用域?
作用域也就是作用范围,为了函数内的变量不影响到全局
9、global和nonlocal
global:强制转换成全局变量
nonlocal:让内部函数中的变量在上一层函数中生效,如果上一层函数中没有,就修改上上层的,依次类推,但是不会修改全局的
10、什么是lambda表达式?
lambda表达式也叫做匿名函数(一些简单的需要用函数去解决的问题)
11、一行打印九九乘法表:
print('\n'.join(''.join([ '%s*%s=%-3s' %(i,j,i*j) for j in range(1,i+1) ])for i in range(1,10)))
二、Rest api
1、什么是API?
答:API就是接口,提供的url,接口有两个用途:
1、 为别人提供服务
2、 前后端分离、一个写vue、一个写后端,他们之间是通过发送ajax请求
2、你为什么要做前后端分离?
答:1、如果更新了数据,web端页面也要改,后端也要改,重复开发了
2、用前端框架开发的时候用的是vue框架,用vue框架搭建速度比较快
3、 专门为它提供json数据
3、什么是rest api规范?
答:之前我们是没有用rest api规范的,都是通过django的url自己来做的,后来我们选择用了rest api,用了restapi 就得遵循他的规范,比如
URL:通过method不同来区分不同的行为,比如get ,post ,put ,patch , delete 等
对于url是面向资源的,一般吧它写成名词的。www.luffcity.com/api/v1/名词。
版本:
可以放在url上 ,也可以放到请求头中(但是我们一般不这样做),也可以放在子域名上(放在子域名上会存在跨域的问题,)
Method
Get :获取数据
Post:创建数据
Patch:部分修改
Put :全部修改
DELETE:删除数据
Options:如果有跨域,会先发一个option请求,先做预检,完了在执行自己发的请求
状态码,不同的请求会有不同的状态码
200:响应成功
302:重定向
403:Forbidden
404:找不到页面
500:服务端代码有误
筛选条件,如果记录的数据过多,服务器本可能都将他们返回给用户,API应该提供参数,过滤返回结果。
错误信息
hypermedia api :超链接
{
id: 1,
name "8级",
part: http://www.luffycity.com/group/1/
}
4、 你们什么时候用的版本?
答:在更新迭代的时候,可以用到版本,当一期的版本开发完,二期的版本开发完,可以通过版本来做
5、Rest api 是规范,restful frame work 实现了restful api规范
三、restful frame work
1、谈谈你对restful framework的认识?
答:我们一开始是没有用restful framework,用django也能实现。不过它为我们提供了一些api接口,如果用django写的话就得自己写装饰器,中间件什么的,但是它为我们事先提供了一部分接口,常用的有认证,权限的判断,访问频率限制等,我们只需要按照人家的规范,只需要写几个类就好了,或者在配置文件里面配置一下就好了,不用我们自己在写装饰器,中间件什么的了,根据他的规范来写,尤其是在用户访问频率限制的时候,人家里面都已经封装好了,我们直接调用它的方法就行了。
'DEFAULT_THROTTLE_RATES':{
'xxx':'2/minute' #2分钟
}
2、restful framework有什么好处?
答:1、他为我们实现了一些功能
2、他的设计比较好、我觉的单独视图和全局配置就设计的很好,类似于django的中间件,通过importlib+反射来实现,以后在写代码的时候如果要做动态配置的时候,可以通过它来实现。动态配置可扩展(短信,邮件,微信等提醒)
3、说说restful framework的原理?
答:我们写的时候是基于CBV模式写的,这个和django中的CBV是一样的,请求先进来会走dispatch方法,根据请求方法不同反射执行不同的方法。而django rest framework里面的五大功能,都是放在dispath里面实现的。
我们写的类是继承APIView的View,去执行它的dispatch(先找自己的,自己没有就找父类的。)
为什么请求一进来就执行dispatch方法?
请求进来到达路由.as_view(),在as_view里面return了一个view函数
请求进来先执行一个view函数
obj = cls() #就是CBV实例化的对象
return self.dispatch() #最终返回了一个dispatch,所以请求一进来就执行dispatch了
执行dispath流程:
封装request
版本
认证
类
class MyAuthentcate(BaseAuthentication):
'''检查用户是否存在,如果存在就返回user和auth,如果没有就返回'''
def authenticate(self, request):
token = request.query_params.get('token')
obj = models.UserInfo.objects.filter(token=token).first()
if obj:
return (obj.username,obj.token)
return None #表示我不处理
def authenticate_header(self, request):
pass #这个函数是验证不成功的时候执行的函数
返回值
可以有三种返回值
Return None #表示不处理
Return (user,auth) #认证成功后返回用户信息
Raise 异常 #也可以抛异常
配置
单独视图
class IndexView(APIView):
authentication_classes = [MyAuthentication,]
全局配置
REST_FRAMEWORK = {
'UNAUTHENTICATED_USER': None, #表示是匿名用户
'UNAUTHENTICATED_TOKEN': None,
"DEFAULT_AUTHENTICATION_CLASSES": [
"app02.utils.MyAuthentication",
],
}
权限
类
class MyPermission(BasePermission):
message='无权访问'
def has_permission(self, request, view):
if request.user:
return True #true表示有权限
return False #false表示无权限
def has_object_permission(self,request,view):
pass
返回值
Return True 有权限
Return False 无权限
Return exceptiions.PermissionDenied(detail=’错误信息’) #自己指定错误信息
配置
视图
class IndexView(APIView):
permission_classes = [MyPermission,]
全局
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": [
# "app02.utils.MyPermission",
],
}
限流
类
allow_request()/wait() PS:scope=’wdp_user’
返回值
Return True 不限制
Return False 限制
配置
视图:
class IndexView(APIView):
throttle_classes=[AnonThrottle,UserThrottle,]
def get(self,request,*args,**kwargs):
self.dispatch
return Response('访问首页')
全局
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES":[],
'DEFAULT_THROTTLE_RATES':{
'wdp_anon':'5/minute',
'wdp_user':'10/minute',
}
}
序列化
视图
、APIView
GenericAPIView(APIView)
GenericViewSet(ViewSetMixin, generics.GenericAPIView)
ModelViewSet(mixins.CreateModelMixin 增
,mixins.RetrieveModelMixin, 查一条
mixins.UpdateModelMixin, 修改
mixins.DestroyModelMixin, 删除
mixins.ListModelMixin,GenericViewSet 查多条
)
解析器
如果发送的是json数据的话,可以在request.data里面取值
而django中会在request.body中取值,获取的值是bytes类型的,还的decode,loads一下,明显djangorestframwork明显方便的多
分页
基于limit offset 做分页
基于页码做分页
基于cursor做分页
方式a、记录当前访问页数的数据id
- 方式b、最多显示120页等
- 方式c、只显示上一页,下一页,不让选择页码,对页码进行加密
路由
渲染器
四、网络编程和并发编程
进程与线程的表示:
Process 进程
Threading 线程
1、并发的本质是什么?
答:切换+保存状态
并发:看起来是同时运行的,在多个任务里面来回切,切的时候保存状态、遇到IO阻塞的时候才切,
2、进程、线程、协程的区别?谈谈你对他们的认识?
答:
工作的最小单位是进程;一个进程里面可以开多个线程;
而协程是程序员可以人为的分配先执行这个后执行那个
进程:一个程序正在运行的过程
线程:一个流水线工作的过程,一条流水线必须属于一个车间,而这个车间的工作过程 就是进程。所以说进程里面是包括线程的。所以进程里面真正干活的是线程
协程:一个任务运行完,切换到另一个任务。单线程下实现并发
3、什么是协程?
答:协程是一个任务运行完,切到另一个任务,是程序员可以人为的分配先执行这个后执行那个
单线程下实现并发。
4、为什么要使用生产者和消费者模型?
答:在多线程开发过程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者处理能力大于生产者,那么消费者就等生产者。就这样形成了互相等的形式。为了解决这个为题所以才引进了生产者和消费者模型
5、生产者和消费者模型
答:使用生产者和消费者模型能够绝大多数的解决并发问题
6、什么是生产者与消费者模型?
答:生产者消费者模型是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通信,而是通过阻塞队列进行通信。所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不直接找生产者要,而是直接从阻塞队列里面去取数据。队列就相当于一个缓存区,平衡了生产者和消费者的处理能力。
7线程池的应用:采集资产管理
8、进程间数据怎么共享?
答:是通过Manager来实现数据共享的。
IPC (进程间的三种通信方式)
Queue 队列:队列类似于一条管道,元素先进先出。
Pipe管道:管道相当于对列, 但是管道不自动加锁
Manager 共享数据:共享数据也没有加锁的功能
因为进程之间的数据是隔离的,要想进行数据共享就得通过以上的方式来实现数据共享,推荐用对列的方式
而线程之间的数据是共享的,如果想实现数据隔离怎么实现?
9、线程之间数据是怎么隔离的?
答:本地线程:保证每个线程都只有自己的一份数据,在操作时不会影响别人的,即使是多线程,自己的值也是互相隔离的。
10、实现并发有哪些手段?
答:开多进程,开多线程,进程池和线程池(current.future模块),协程gevent :单线程下实现并发
11、同步和异步?
答:同步:提交完任务后在原地等着
异步:提交完任务之后就走了,不用等了,吧结果丢给了回调函数
12、哪里用过多进程?
答:部署的时候用过,但是代码里面没有涉及到大量的计算。
计算密集型的用多进程
IO密集型的开多线程
13、什么是协程?
人为控制的线程执行流程,先执行这个再执行那个
可以通过yield自己控制,
Greenlet
基于Gevent实现协程
14、进程和线程的区别?
答: 1、创建线程比创建进程开销小(开一个进程、里面就有空间了,而线程在进程里面)
2、多线程一定是在一个进程里面开启的,共享进程里面的数据
3、线程启动速度快
4、同一进程下的多线程共享进程里面的数据
多个进程之间的内存空间是数据隔离的
5、线程可以跟它所在的进程之内的线程通信
15、GIL全局解释器锁和自己加的锁Lock互斥锁或者Rlock锁
GIL与Lock锁是两把锁,他们保护的数据不一样,GIT锁是解释器级别的(所以保护的是解释器级别的数据,比如垃圾回收的数据),Lock是保护用户自己开发的应用程序的数据,很明显GIL不负责这件事。
为了解决死锁现象,加了一把Rlock锁。死锁现象就是形成了互相等待的过程
简单描述GIL对Python性能的影响
使Python不能真正意义上的多线程,同一时刻只能有一个线程运行。
5.1 Python的GIL在单核情况下对性能的影响可以忽略不计,几乎没有。
5.2 Python由于其GIL的存在在多核CPU的情况下Thread的表现真的是非常的糟糕,但是Process则不受GIL的影响。
5.3 Python内置的数据类是不适合用于大量的数学计算的,当然这也不仅仅是Python的问题,其它完全面向对象的语言都有这个问题, 要进行大量的数学计算就要用把代码移到C/C++中去实现,这样不仅可以去除gil的影响,更可以让性能获得几十倍上百倍的提升, 或者用numpy之类的扩展在执行科学计算时也可以让性能大幅的提升。
5.4 Python慢其实就是慢在数字计算上,想想就知道,如果每一个数字都是一个对象, 在计算的时候就免不了不断的为对象申请内存,释放内存,速度肯定就慢下来。
5.5 但是,Python对数据结构的操作是非常高效的,像Python内置的强大的dict,str,list等类, 不是说大话,其处理的速度真的可以和C媲美,因为它们的实现本身就是用C实现的。 我们在编程刚入门的时候就被告知:数据结构+算法=程序,这个道理也许只会在用Python这样的语言时才会有更切身的体会。
5.6 在用Python开发程序时,你不得不花点时间在性能优化上来, 过程也很简单:用cProfile类查找出比较耗时的操作,然后将其移到C中去实现, 另外,如果是使用多核CPU的情况,一定要小心使用Thread,尽量用Process来替代Thread,通过本文对GIL的分析,将对性能的优化提供很好的帮助。 其实,Python的性能优化过程也是程序开发中有挑战又非常有成就感的部分。
5.7 但是,记住一点,不要过早的对程序进行优化,过早优化是罪恶之源 ---Donald Knuth。前期开发应该把注意力放在功能实现以及代码的可读性和可维护性上来。
5.8 最后,愿以一句话作为本篇文件的结束语:都说爱一个人就要爱他(她)的全部,包括他(她)的缺点,对人如此,对物呢?
GIL与Lock锁是两把锁,他们保护的数据不一样,GIT锁是解释器级别的(所以保护的是解释器级别的数据,比如垃圾回收的数据),Lock是保护用户自己开发的应用程序的数据,很明显GIL不负责这件事。
为了解决死锁现象,加了一把Rlock锁。死锁现象就是形成了互相等待的过程
16、加锁和不加锁什么区别?
数据共享就会有竞争,所以考虑加锁。让串行执行,速度慢,数据安全。
如果不加锁,并发执行,速度快,数据不安全。
17、锁的格式
Import threding
Mutex = theading.lock()
Mutex.aquire() #加锁
‘’对公共数据的操作’’’
Mutex.release() #释放锁
18、TCP和UDP
TCp:双向链接,客户端向服务端发送消息后,等待服务端回复消息后才算发送成功。
缺点:速度慢
优点:可靠
UDP:没有链接、直接发送
优点:速度快
缺点:不可靠
19、三次握手(连接)和四次挥手(断开):
三次握手的目的:建立双向通信链路。SYN代表客户端向服务端发送的一个请求,ACK代表服务端向客户端发送的回应。
三次握手就像谈恋爱确定关系一样,四次挥手就像分手一样。此处只是打比方而已。
20、七层协议
1、物理层:常见的物理设备:中继器、集线器、双绞线
功能:主要基于电器特性发送高低电压,高电压对应数字1,低电压对应数字0(提供电信号)
2、数据链路层:网桥、以太网交换机、网卡
功能:定义了电信号的分组方式
3、网路层:路由器、三层交换机
功能:引入一套新的地址用来区分不同的广播域/子网,这套地址即网络地址。
4、传输层:四层交换机、四层的路由器
功能:建立端口到端口的通信。
5、会话层
6、表示层
7、应用层
功能:规定应用程序的数据格式。
7.IPC
进程之间的通信有两种实现方式:管道和队列
进程之间的数据共享:Manager
tasklist 查看进程
tasklist | findstr pycharm #(findstr是进行过滤的),|就是管道(tasklist执行的内容就放到管道里面了,管道后面的findstr pycharm就接收了)
进程间通信技术包括消息传递、同步、共享内存和远程过程调用(RFC)。IPC是一种标准的Unix通信机制
线程之间数据数据隔离:
本地线程:保证每个线程都只有自己的一份数据,在操作时不会影响别人的,即使是多线程,自己的值也是互相隔离的
8.lock与rlock,信号量也是一种锁
Lock是互斥锁
Rlock是为了解决死锁问题出现的
死锁是指是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
信号量:是产生的一对进程/线程,即产生了多个任务都去抢那一把锁。
总结:
1.多核也就是多个cpu
(1) cpu越多,提高的是计算的性能
(2) 如果程序是IO操作的时候(多核和单核是一样的),再多的cpu也没有什么意义。
2.实现并发
(1)
五、mysql数据库
数据库的范式:
第一范式:是指数据库表中的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性
第二范式:第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。
1、mysql的数据库引擎有那些?分别有什么区别?
Mysiam :支持全文索引,不支持行锁,支持表锁
Innodb:支持事务,支持行锁,支持表锁
2、什么是行锁什么是表锁?
行锁:根据主键找到数据
Select * from tb2 where nid=3 for update;
表锁:
根据主键,未找到数据
Select * from tb2 where nid=30 for update;
根据主键,数据不明确
Select * from tb2 where nid<2 for update;
Select * from tb2 where nid!=3 for update;
根据非主键查找
Select * from tb2 where name=’alex’ for update;
3、mysql怎么提高性能?
当数据量越来越大的时候,查询速度会越来越慢,这就可以用加索引的方式提高查询速度
索引分类?
1、 普通索引 index
2、主键索引 primary key
3、唯一索引 unique
4、联合索引 (遵循最左匹配原则:mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配)
Primary key (id ,name) 联合主键索引
Unique(id , name) 联合唯一索引
Index(id , name)联合普通索引
5、覆盖索引:在索引表里面吧所有的值拿到
6、合并索引:两个单独的索引合起来一起用
索引命中:
创建索引
索引的种类?
Hash类型的索引:查询单条快,范围查询慢。
Btree类型的索引 :b+树,层次越多,数据量指数级增长(ennodb默认的就是Btree类型)
4、如何索引命中?:
创建索引,未命中
命中:相当于精确查询。。。in,like就不命中
排序条件为索引,则select字段必须也是索引字段,否则无法命中
索引的种类?
Hash类型的索引:查询单条快,范围查询慢。
Btree类型的索引 :b+树,层次越多,数据量指数级增长(ennodb默认的就是Btree类型)
5、 在django的model操作,怎么提高性能?
Select_related:一对多使用,查询主动做连表操作
Prefetch_related:多对多或者一对多的时候使用,不做连表,做多次查询
6、 数据库怎么创建索引?
create index account_count on table_name 字段名
怎么创建组合索引?
create index account_count on table_name (字段名, 字段名)
7、 mysql有那些数据类型?
a) 数字
b) 字符
c) 日期
d) 枚举和集合
5、你对数据库优化的方案有哪些?
减少FK
允许数据冗余
不经常更改的数据放入内存 models中的choice
Select *
6、Python操作mysql?
Pymysql
Django 中默认的是MySQldb,如何改成pymysql。
放在项目的__init__里面Pymysql.install_as_mysqldb()
7、函数、视图、存储过程、触发器
函数、视图、存储过程、触发器都是存在数据库的。
8、关系型数据库和非关系型数据库
关系型数据库:mysql 、oracle
非关系型数据库:redis 、memcache
9、redis和memcache非关系型数据库和mysql关系型数据库的不同?
Redis和memcache都是在内存中存放的
Redis是支持持久化的,memcache是不支持的,相对于memchache慢一点。但是比mysql关系型数据库快的多。因为mysql的数据是存在硬盘的,redis是存在内存中的
10、Memchache和redis的相同点和不同点?
(1) Redis:Key:value键值对
Name:’yaa’,
Name:[]
Name:{“”:””} #散列表
Name:{} #集合
Name :”” #字符串
Memchache:key:value
Name:”” #只支持字符串
(2) Redis是支持持久化的,memcache是不支持的,相对于memchache慢一点
(3) Memchache一断电就数据没有了,redis支持持久化可以存一点数据,所以安全性不高
11、redis和mysql的优缺点?
Redis :优点是存在内存、速度快;缺点是不安全
Mysql:优点是安全,是存在硬盘的;缺点是查询速度慢。
12.索引:
本质通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。
10python使用pymsql来连接数据库:
一定要注意sql注入
11.你们如何做的数据库备份?
Mysql数据备份:
- 物理备份:直接复制数据文件,适用于大型数据库环境
- 逻辑备份:备份地是建表,建库,插入等操作所执行SQL语句,适用于中小型数据库,效率相对较低
- 导出表:将表导入到文本文件中。
12数据库里的视图,触发器,事务
视图:
视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,可以将该结果集当做表来使用。
但是视图有明显的效率问题,并且视图是存放在数据库中,如果我们程序中使用的sql过分依赖数据库中的视图,即强耦合,那就意味着扩展sql极为不便,因此不推荐使用。
触发器:
-- 触发器:某种程序触发了工具的运行
-- 触发器不能主动调用,只有触发了某种行为才会调用触发器的执行
-- 插入一条记录就触发一次
-- 还是建议不要用触发器,因为这是BDA管理的,还是不如你在程序里面直接写比较方便
事务:
-- 事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,
-- 即可回滚到原来的状态,从而保证数据库数据完整性。
-- 事务也就是要么都成功,要么都不成功
-- 事务就是由一堆sql语句组成的
存储过程:
存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql
-- 存储过程的优点:
-- 1.程序与数据实现解耦
-- 2.减少网络传输的数据量
-- 但是看似很完美,还是不推荐你使用
13.程序与数据库结合使用的三种方式:
#方式一:
MySQL:存储过程
程序:调用存储过程
#方式二:
MySQL:
程序:纯SQL语句
#方式三:
MySQL:
程序:类和对象,即ORM(本质还是纯SQL语句)
14 数据库基本操作:
数据库的增删改查(sql):
增:create database db1;
删:drop database db1;
改: alter database db1 charset utf8;
查:show databases;
表的增删改查:
增:create table t1(id int ,name char );
删:drop table t1;
改:
插入数据:inset into test(id,name) values(1,’*’)
查: show tables;
Show create table t1; 查看指定的表
数据库的指定引擎:
Innodb:出现2个文件
Myisam:会出现3个文件
Memory:只有表结构没有表数据,是创建到内存中的
15.查看数据库的引擎:
查看MySQL的引擎 Show engines:
查看默认引擎: show variables like '%storage_engine%';
查看当前表的引擎: show create table 表名;
16.数据库权限的设置
创建用户:
Create user ‘egon’@‘192.168.1.%’ identified by ‘123’
授权文件夹:
grant select on *.* ‘egon’@’localhost’ identified by
六、Django
1、Django的缓存机制?
Django默认有缓存机制,它能为我们做什么事情?
6中缓存方式
1、 内存缓存
2、 文件缓存
3、 开发调试缓存
4、 数据库缓存
5、 Memcache缓存
经常使用的有文件缓存和mecache缓存
3.Django 基本命令: 1 pip3 install django
有名分组和无名分组:(?P<name>pattern)
视图返回: HTTPresponse render response
获取多个键值对的时候用:request.POST.getlist("hobby")
在模板中:复杂的数据结构用句点符 . 句点符也可以用来引用对象的方法.
HTTP协议:是属于应用层的面向对象的协议
特点:简单快速 灵活 无连接 无状态
Http协议的格式: 请求首行 请求头信息 空行 请求体
HTTP默认的请求方法就是GET
* 没有请求体
* 数据量有限制!
* GET请求数据会暴露在浏览器的地址栏中
GET请求常用的操作:
1. 在浏览器的地址栏中直接给出URL,那么就一定是GET请求
2. 点击页面上的超链接也一定是GET请求
3. 提交表单时,表单默认使用GET请求,但可以设置为POST
GET和POST的区别
1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的Body中.
2. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
3. GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。
4. GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.
Wsgi wsgiref 实现这个方法
MTV模型:
M代表的是Model
T代表的是Template
V代表是的View
模板层:模板=html+模板语法 模板继承用 extends
数据库改为mysql 需要改两个方面:第一是注销掉原来的数据库,改为mysql 第二步是:在项目的__init__里面加上 两句 import mysql pymysql.instsll_as_MySQLdb()
ORM:13个API和2个补充only derfer values 拿到的是字典 values_list 拿到的是元祖
2.Django生命周期: wasgi 中间件 路由 视图 ORM 渲染
七、Flask
什么是本地线程?
什么是上下文管理?
本质:每一个线程都会创建一个
1、Django和Flask的比较?
Django大而全:
无socket,依赖于第三方wsgiref模块实现了wsigi协议,中间件 ,视图(CBV,FBV)
模板、cookie、session 、ORM、Admin、Form、缓存、信号、序列化
Flask小而精:
无socket,依赖于是第三方werkzeug模块实现wsgi协议,中间件(扩展), 视图(CBV,FBV)
无模板、用的是第三方JinJa2模板,无ORM 、cookie、session(比较弱)
2、保存session的数据存到了浏览器上,
优点:减轻了服务端的压力
缺点:不安全
8、 路由参数
redirect_to:直接重定向,原url有参数时,跳转使也得传参,注意:不用加类型
@app.route('/test',strict_slashes=True) #当为True时,url后面必须不加斜杠
# =============== 子域名访问============
@app.route("/static_index", subdomain="admin")
扩展Flask的路由系统,让他支持正则,这个类必须这样写,必须去继承BaseConverter
@app.route('/index/<regex("\d+"):nid>',endpoint='xx')
9、 请求响应相关
- request
- request.form #POST请求
- request.args #GET请求 字典形式的
- request.querystring #GET请求,bytes形式的
- response
- return render_tempalte()
- return redirect()
- return ""
v = make_response(返回值) #把返回的值包在了这个函数里面
- session
- 存在浏览器上,并且是加密的
- 依赖于:secret_key
5、闪现的本质是什么?
1、本质:flash是基于session创建的,flash支持往里边放值,只要你取一下就没有了,相当于pop了一下。不仅把值取走,而且把session里的东西去掉
6、flask里面的扩展,相当于django中的中间件
@app.before_request
def process_request1():
print('process_request1')
@app.after_request
def process_response1(response):
print('process_response1')
return response
7、蓝图(flask中多py文件拆分都要用到蓝图)
如果代码非常多,要进行归类。不同的功能放在不同的文件,吧相关的视图函数也放进去。蓝图也就是对flask的目录结构进行分配(应用于小,中型的程序)
8、flask是怎么操作数据库的?
flask中是没有ORM的,如果在flask里面连接数据库有两种方式
一:pymysql
二:SQLAlchemy
是python 操作数据库的一个库。能够进行 orm 映射官方文档 sqlchemy
SQLAlchemy“采用简单的Python语言,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型”。SQLAlchemy的理念是,SQL数据库的量级和性能重要于对象集合;而对象集合的抽象又重要于表和行。
9、基于DButils实现的数据库连接池有两种模式:
模式一:为每一个线程创建一个链接(是基于本地线程来实现的。thread.local),每个线程独立使用自己的数据库链接,该线程关闭不是真正的关闭,本线程再次调用时,还是使用的最开始创建的链接,直到线程终止,数据库链接才关闭
模式二:创建一个链接池,为所有线程提供连接,使用时来进行获取,使用完毕后在放回到连接池。
PS:假设最大链接数有10个,其实也就是一个列表,当你pop一个,人家会在append一个,链接池的所有的链接都是按照排队的这样的方式来链接的。
链接池里所有的链接都能重复使用,共享的, 即实现了并发,又防止了链接次数太多
10、什么是本地线程?
:保证每个线程都只有自己的一份数据,在操作时不会影响别人的,即使是多线程,自己的值也是互相隔离的
13、 上下文管理
a、类似于本地线程
创建Local类:
{
线程或协程唯一标识: { 'stack':[request],'xxx':[session,] },
线程或协程唯一标识: { 'stack':[] },
线程或协程唯一标识: { 'stack':[] },
线程或协程唯一标识: { 'stack':[] },
}
b、上下文管理的本质
每一个线程都会创建一个上面那样的结构,
当请求进来之后,将请求相关数据添加到列表里面[request,],以后如果使用时,就去读取
列表中的数据,请求完成之后,将request从列表中移除
12、witform组件
WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证
14、 flask-session
flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,该组件则将支持sessio n保存到多个地方,如:
八、常用排序算法
冒泡排序:就是两层for循环一层控制的是趟数,一层是进行比较
选择排序:就是每次选择比当前还小的值进行交换 还有一步就是要判断那个值是否改变了,只有改变了才需要交换下
插入排序:分为有序区和无序区 每次用拿到的数据和有序区的所有数据进行比较大小
快排:首先,找到第一个值作为中间值,左边都比它小右边都比它大,然后在使用整个快排方法对左边和右边进行递归调用。
归并排序:也是用到了递归调用;假设分为2部分,在生成一个列表,把两个列表的数据按照大小放入,剩下的一起放入。
堆排序:先创建堆,然后找它的左子节点,判断是否比子节点大如果大接着继续往下判断,如果过没有就把那个值放在子节点上(干部)
1、冒泡排序
思路:列表中两个相邻的数比较大小,如果前边的比后边的大,那么这两个就互换位置
def bubblr_sort(li):
for i in range(1,len(li)-1):#表示趟数
change = True
for j in range(len(li)-i): #表示无序区,无序区的范围为0,len(li)-i
if li[j] > li[j+1]:
li[j],li[j+1] = li[j+1],li[j]
change = True
if not change:
return
li = list(range(10))
import random
random.shuffle(li)
print(li)
bubblr_sort(li)
print(li)
2、直接插入排序
思路:元素被分为有序区和无序区两部分。最初有序区只有一个元素。每次从
无序区只给你选择一个元素,插入到有序区的位置,直到无序区变空。
def insert_sort(li):
for i in range(0,len(li)) : #无序区
tmp = li[i] #表示摸到的牌
j = i-1 #指向有序区最后一个位置
while li[j] >tmp and j>=0:
li[j+1] = li[j] #向后移动
j-=1
li[j+1] = tmp
li = list(range(10))
import random
random.shuffle(li)
print(li)
insert_sort(li)
print(li)
3、选择排序
思路:一趟遍历完记录最小的数,放在第一个位置;再遍历一趟, 取出剩余记录列表中的最小的数,继续放置
def choice_sort(li):
for i in range(len(li)-1): #i即表示躺数,又表示无序区开始的位置
min = i #表示最小数的位置
for j in range(i+1,len(li)): #后一个位置的范围
if li[j] < li[min] :#两个数进行比较,如果后面的一个比最小的还小,说明找到 了
min = j
li[i] ,li[min] = li[min] ,li[i]
li = list(range(10))
import random
random.shuffle(li)
print(li)
choice_sort(li)
print(li)
=================以上的时间复杂度都是O(n^2)=============
4、快速排序
# 思路:
# 1、取一个元素p(第一个位置),使元素p归位(去它该去的地方)
# 2、列表被p分成两部分,左边的都比p小,右边的都比p大
# 算法关键点:
# 递归
# 归位
def partition(li,left,right):
'''归位函数'''
tmp = li[left] #先吧5取出来
while left < right:
while left <right and li[right] >=tmp:
right -=1 ##从右边找比5小的数,填充到5的位置
li[left] = li[right]
while left < right and li[left] <=tmp:
left +=1 # 从左边找比5大的数字放在右边的空位
li[right] = li[left]
li[left] = tmp ##当跳出循环条件的时候说明找到了,并且把拿出来的5在放进去
return left
def quick_sort(li,left,right):
if left < right: #至少有两个元素,才能进行递归
mid = partition(li,left,right)
quick_sort(li,left,mid-1) #递归,右边的-1
quick_sort(li,mid+1,right) #递归,左边的-1
li = list(range(100))
import random
random.shuffle(li)
print(li)
quick_sort(li,0,len(li)-1)
print(li)
5、堆排序
# 堆排序过程
# 建立堆
# 得到堆顶元素,为最大的元素
# 去掉堆顶,将堆最后一个元素放在堆顶,此时可以通过一次调整使堆有序
# 堆顶元素为第二大元素
# 重复步骤三知道堆变空
6、归并排序
# 将列表分成两段,将其合成一个有序列表
# 先分解后合并
# 分解:将列表越分越小,直至分成一个元素
# 终止条件:一个元素是有序的
# 合并:将两个有序列表归并,列表越来越大
import random
def merge(li, low, mid, high):
# 一次归并
'''
:param li: 列表
:param low: 起始位置
:param mid: 按照那个位置分
:param high: 最后位置
:return:
'''
i = low
j = mid + 1
ltmp = []
while i <= mid and j <= high:
if li[i] < li[j]:
ltmp.append(li[i])
i += 1
else:
ltmp.append(li[j])
j += 1
while i <= mid:
ltmp.append(li[i])
i += 1
while j <= high:
ltmp.append(li[j])
j += 1
li[low:high+1] = ltmp
def _merge_sort(li, low, high):
if low < high: # 至少两个元素
mid = (low + high) // 2
_merge_sort(li, low, mid)
_merge_sort(li, mid+1, high)
merge(li, low, mid, high)
print(li[low:high+1])
def merge_sort(li):
return _merge_sort(li, 0, len(li)-1)
li = list(range(16))
random.shuffle(li)
print(li)
merge_sort(li)
print(li)
5、 常用算法总结
快速排序,归并排序,堆排序他们的时间复杂度都是O(nlogn)
三种排序算法的缺点
a) 快速排序:极端情况下排序效率低
b) 归并排序:需要额外的内存开销
c) 堆排序:在快的排序算法中相对较慢
挨着换的稳定,不挨着换的不稳定
九、面向对象
1、你对函数式编程和面向对象编程的理解?
答:从写代码的角度来说,
函数式编程是:将公共能功能编写成一个函数,通过参数的不同来产出不同的结果
面向对象编程是:有三大特性:封装、继承、多态
多态:鸭子类型,由于Python是非强类型的,例如传入的值不管是什么,只要有我自己想调用的方法就行了,本身就是多态的。
封装:
数据的封装
方法和属性的封装
继承:在Python中是有多继承的,当前类中没有方法或者其他字段,去基类中查找。
派生类:谁继承谁就是派生类,也就是子类
2、 经典类和新式类的区别?
Python2中有两种:
经典类:不继承obj
新式类:继承object
多继承的时候查找顺序是不同的
经典类:深度优先
新式类:广度优先
Python3中只有新式类
十、函数
1、*args,**kwargs是干什么用的?
2、传参数的时候传的是引用还是值?
看是什么类型
不管是字符串,数字,还是列表都是传的引用,只不过最终现象不一样。
10、 什么是闭包?
答:内部函数包含对外部函数作用域而非全局作用域名字的引用。
装饰器就是必用闭包的原理
11、 怎么理解深浅拷贝?
深拷贝deepcopy:会拷贝父对象及其子对象
浅拷贝copy.copy():只会拷贝父对象,不会拷贝子对象
比如,如果一个对象里面又包含了另外一个对象,浅拷贝的时候只是把外部对象拷贝了一份
如果是深拷贝,会把外部的拷贝,吧内部的也拷贝
在什么时候用到了拷贝?
Request.GET 是不一个QueryDict对象,是不可以修改的,需要加一个参数_mutable = True才可以修改,为了不影响其他的时候,我们可以拷贝一份,在做修改。
12、 编码问题
Python3中的字符串是unicode
Python2中的字符串是字节
13、 装饰器是什么?什么时候用过?
答:在不改变原有代码的基础上在执行之前或者执行之后做点操作
Flask的路由是用装饰器做的
用户认证的时候也用了装饰器,但是如果视图多的话可以用中间件的形式
装饰器的执行流程是什么样的?
答:在Crm中,获取返回的数据需如果不是自己想要的格式,可以进行二次加工,再在模板中循环展示时,可使用生成器减少循环。
14、 什么是可迭代对象?迭代器?生成器?
答:可迭代对象:含有__iter__的就是可迭代对象,返回一个迭代器
迭代器:含有__next__方法的就是迭代器,只能往前更新迭代,不能往后退。
生成器:基于函数+yield实现,即可以取值,也可以生成值,它也有一个__next__方法,具有迭代器的特性。返回一个生成器
你在哪里用过生成器?
答:
15、
十一、Python基础
2、 为什么学Python?
答:公司项目用Python
容易上手
Python火
(1)大学的时候学的测试,出去直接找工作有点难度,因为大学学的都是些基础,没有实战的项目,找工作也不好找,就想着培训一下,后来网上搜了一下,看python挺火的
工资待遇啥的也都不错,心里就想着培训这个,所以就学习了python
(2) 学校社团有学习Python的,我那时候感兴趣,就报名了。在那里面成长了不少,一个组一个组的分配学习任务,每天一块讨论问题,学着学着感觉python语言比起java的语言简练了,就慢慢的自学、通过看网上的视频,看官方文档等。
3、 字符串常见的方法有哪些?
答:strip(), split() , startwiths() ,index() , endwiths() ,
4、 列表常见方法?
5、 字典常见方法?
6、 元组常见方法?
7、 结合常见方法?
8、 Collections模块
a) 有序字典
b) 命名元组
c) 默认值字典
d) 双向队列 dequeue
9、 unicode和utf-8的区别?
unicode:优点是字符转换数字的时候速度快,缺点是占用空间大
utf-8:优点是精准,可变长,转换速度慢,缺点是节省空间
【unicode:多的字符都是2bytes,优点是字符转换数字的时候速度快,缺点是占用空间大】
【utf-8:精准,可变长,优点是节省空间;缺点是转换速度慢,因为每次转换都需要计算出需要多长bytes才能准确表示】
10、 Python2和Python3的区别?
答:我接触的他们的最大的区别是编码的不同
(1)Python2里面默认是ascII , python2中的字符串就是bytes,python2中的字符串前面加u,就是unicode
Python3里面默认的是unicode,python3中的字符串被识别为unicode,python3中的字符串 encede得到bytes
(2) python2中的字符串有str和unicode两种类型
Python3中的字符串有str和bytes两种类型
(3)Xrange()返回的是一个可迭代对象 和range()返回的是一个列表
(4)Python2中的文件读取Xreadlines 和 Python3中的readline
10.字符编码
如何让计算机读懂人类的字符?
必须经过一个过程:
#字符--------(翻译过程)------->数字
#这个过程实际就是一个字符如何对应一个特定数字的标准,这个标准称之为字符编码
Ascii:用1个字节(8位二进制)代表一个字符 8bit可以表示0-2**8-1种变化,即可表示256个字符
Unicode(定长):常用2个字节(16位二进制)代表一个字符,生僻字需要用4个字节
Gbk:2Bytes代表一个中文字符,1Bytes表示一个英文字符
Utf-8(可变长):对英文字符只用1Bytes,对中文字符采用3Bytes,
总结:内存中统一采用Unicode,浪费空间来换取可以转换成任意编码(不乱码),硬盘可以采用各种编码,如utf-8,保证存放于硬盘或者基于网络传输数据的数据量很小,提交传输效率与稳定性。
以什么编码存的,就要以什么编码取出
Ps:内存固定使用unicode编码,我们可以控制的编码是往硬盘存放或者基于网络传输
数据最先产生于内存是unicode格式,要想传输需要转成bytes格式。
Unicode –》encode(utf-8)—》bytes
拿到bytes,就可以往文件内存放或者基于网络传输
Bytes---》decode(gbk)—》unicode
Python3中字符串被识别成unicode
Python3中的字符串encode得到bytes
Python2中的字符串就是bytes
Python2中在字符串前加u就是unicode
十二、常用模块
1、你用过哪些模块?
Json /pickle
Time :时间格式的转化
Random :随机数相关
Sys:与Python解释器相关
import sys
print(sys.argv) #实现从程序外部向程序传递参数。(在命令行里面输打开路径执行)
name=sys.argv[1] #命令行参数List,第一个元素是程序的本身路径
password = sys.argv[2]
if name=='egon' and password == '123':
print('继续执行程序')
else:
exit()
sys.exit()#退出程序,正常退出时exit(0)
print(sys.version)#获取python解释的版本信息
print(sys.maxsize)#最大能表示的数,与系统多少位有关
print(sys.path)#返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
print(sys.platform)#返回操作系统平台名称
OS模块
Os(模块里的重点):与操作系统相关
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') 可生成多层递归目录
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename("oldname","newname") 重命名文件/目录
os.stat('path/filename') 获取文件/目录信息
os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示
os.popen("bash command) 运行shell命令,获取执行结果
os.environ 获取系统环境变量
os.path
os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。
即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
Re :
Haslib:
Subprocess :执行系统命令
Requests:
Befautiful
10、 正则里面有哪些方法?
Match:只是从字符串的开头进行匹配,也就是说只有在索引为0的位置匹配成功的话才有返回值,如果不是开始位置匹配的话,返回值为none
Search:会把整个字符串扫描一遍,并返回第一个成功匹配的值
Findall
贪婪匹配
常用正则:
邮箱
手机号
Ip
十五、HTTP协议
1、 什么是http协议?
答:就是浏览器和服务器之间进行“沟通”的一种规范。
http协议是属于应用层的协议
2、 http协议的特点?
答:简单快速,灵活,无链接,无状态
3、 http协议常见的请求方式有哪些?
答:get ,post, delete , put ,patch , options ,head ,connect
我常用的就是get ,post, delete , put ,patch , options ,这几个
在restframework里面写接口的时候,用了这些方法
HTTP请求默认的请求方法是GET请求
4、GET请求:
没有请求体;数据量有限制;GET请求请求的数据会放在url上
GET请求常用的操作:
1. 在浏览器的地址栏中直接给出URL,那么就一定是GET请求
2. 点击页面上的超链接也一定是GET请求
3. 提交表单时,表单默认使用GET请求,但可以设置为POST
5、POST请求:
有请求体,
15、GET请求和POST请求的区别?
a 、GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的Body中.
b、GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
c、 GET方式需要使用Request.GET来取得变量的值,而POST方式通过Request.POST来获取变量的值。
d 、GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.
16、http协议格式
1、 请求头和请求体之间是通过\r\n\r\n来分割的
2、 请求体之间是一个\r\n
3、 Get 无请求体
4、 无状态、短连接:socket请求响应断开
5、 请求头代表的意义:
a) User-agent:来源
b) Referer:防盗链
c) Content-type:请求体是什么格式?
最后:项目相关
1、 保障系统(个人博客,报障系统)
项目背景:需要对公司内网运维工作绩效考评,以及对于内网运维工作效率的提高创建知识库的功能,所以才开发这么一个系统
周期:一个人,三周左右
有两大功能:
1、员工填写故障单
2、运维人员接单并处理,两小时内如果不回答,就成别人的了。记录个接单时间,比较接单时间和现在的时间是否相差两小时:
员工通过用户名密码登录到公司内网的系统,如果谁有问题就发送给内网运维。这些运维人员就会接收单,接单的时候会有提醒:比如微信提醒或者邮箱提醒等
#公司的员工发送问题,内网运维接单。
#接单的时候会有提醒:微信提醒/邮箱提醒/rtx提醒(就是企业用的QQ,腾讯通)等
3、常见知识库分类和筛选:
一些常用的问题写到知识库里面,自己去查也就解决了。
在这个知识库里面会有点赞,评论的功能。
常见问题还有分类
4、基于HighChar实现员工工作绩效的对比
5、提醒:微信提醒,邮箱提醒
外网运维:公司的所有网站不挂掉,都是外网运维干的
内网运维:比如你的电脑连不上网络,等是内网运维干的
2、 CRM系统(也可以更改成基于rbac的xxx的管理系统)
以教育行业为例
描述:基于rbac的使用,对系统人员进行权限控制对学校、老师、班级和销售进行统一管理,其中涉及销售的报表和跟进记录,并对销售人员成单比进行统计,这都是可以通过highchart做出来的,以及班级和评分的管理,其中还有对公司会议室开发的会议室预定。
周期:1-2人,3-6月
功能:
1、 基于中间件和session实现自定制rbac权限组件,粒度到按钮级别。(目标是开发一个公共的组件),用了 那些表,流程
2、 基于BootStrap实现页面展示
3、 基于BootStrap datetimepicker(选时间的那个日历)实现会议室
4、 基于HighChart对销售业绩进行可视化显示
5、 参考Django源码 实现自定义stark组件开发,并完成自定制,组合查询等功能
6、 通过django-redis实现session存储
7、 基于Form实现可定制的调查问卷
业务:
用户只要一报名,就有来源,就得把数据录入到客户表里面。每个人都有不同的权限
对于销售来说有一下权限,比如:
基于MOdelForm实现客户数据录入
还有客户跟进的权限,如果第一次跟进的这个人如果3天未跟进,15天未成单,那么这个单子就成公共资源。(跟进记录+3<当前时间)
对于销售经理,可以查看人员成单记录
班级管理
对于班主任:主要做班级管理,沟通记录,问卷(对于问卷也是有权限管理的)
老师:上课记录,检查祖业,上传作业,初始化班级
外包到别人公司给他们公司做的,或者给自己公司做的。
3、 路飞学城(在线教育平台)
描述:系统使用前后端分离的模式,前端使用vue框架,后端使用restframeworl实现。系统主要用于为用户提供学习平台,并创建一对一辅导,并整合用户支付和微信消息的推送和提醒。使
用Git进行协同开发。
周期:半年
团队:
1个UI,1个前端,4个后端,
功能:
基于极验实现的动态验证码
在线视频播放是用CC视频。
基于rest framework实现API 接口
4、 权限管理系统
目的:生成一个独立的组件,到哪都能用
1、 所涉及的表
五个类,七张表
用户表
权限表
角色表
组表
菜单表
角色权限表
用户角色表
2、 实现的功能:
a、编写登录:当用户登录成功的时候设置session
b、判断有没有添加权限,有没有删除权限,有没有编辑权限,粒度到了按钮
具体实现:登录成功之后获取用户所有的权限信息并且保存到session中,获取session中保存的信息,循环url进行正则匹配,如果匹配成功,表示有权限;如果匹配不成功,说明没有权限。这个认证的过程,如果有很多的视图,每一个都要进行认证,所以我们把认证写在了一个中间件里面。当匹配成功的时候,把code保存在了request里面,方便以后判断有没有添加的权限,有没有删除,编辑的权限等。
C、生成菜单:并且让这些菜单分级显示默认展开的组内菜单是红色的。如果是非菜单,默认选中原菜单
具体实现:在设计表的时候设计了一个组内菜单(自关联),当是NULL的时候就说明是可以作为菜单的。
在初始化的时候,初始化权限信息,获取权限并放置到session中,去session中获取到菜单相关信息,匹配url,生成菜单。在这里渲染页面的时候,我们用了自定义的标签@register.includsion_tag("xxx.html") (用includsion_tag自动会读取到这个文件并把返回值在页面上渲染) “在母版中:{%menu_html request%} request是参数,记得要加上{% load rbac %}
5、 博客系统
功能
用户登录
系统主页
左侧菜单系列
显示文章系列
右侧可以放一些其他系列
个人主页
导航条
左侧
个人信息
我的标签
随笔分类
日期归档
右侧
显示文章
个人主页的文章详细以及点赞和评论

浙公网安备 33010602011771号