Python - 面试题分阶段整理
一,基础阶段
迭代器.生成器.装饰器.闭包
1.具有__iter__() 和 __next__()这两个方法的是迭代器
2.具有__iter__()方法就是可迭代对象
3.生成器的本质就是一个迭代器 具有yield关键字就是生成器
4.装饰器的本质就是闭包
在不修改源代码,以及调用方式的情况下,额外的增加新功能
类 登录验证
5.迭代器和生成器的区别: 迭代器是python自带的,生成器是程序员自己写的
6.啥是闭包:嵌套函数内,使用非全局非本层变量就是闭包
闭包干啥:保证数据的安全性,装饰器使用 外层函数返回内层函数的特性!
深浅拷贝:必问
赋值:将多个变量名指向同一个内存地址就是赋值
浅拷贝: 只拷贝第一层元素的地址,只有修改拷贝的数据第一层的时候源数据不受影响
给可变数据类型进行添加的时候源数据会受影响
= 是修改 .append是添加 可变数据类型能够修改和添加,不可变数据类型只能修改
深拷贝:不可变数据类型内存地址公用,可变数据类型新开辟一个空间
标准库,第三方库
标准库:标准库会随着python解释器,一起安装到你的电脑中,他是python组成的一部分
常用的标准库: os 操作系统,time时间,random ,datetime,sys,json, pickle,re
第三方库:virtualenv,django,scrapy,requests,xadmin,celery
反射
通过字符串去操作类对象 或者 模块中的属性方法
hasattr getattr setattr delattr
应用: 可以配合用户的操作或者输入,调用其中的成员,api接口中
二,网络编程
osi七层协议
# 应用层# 表示层# 会话层# 传输层# 网络层# 数据链路层# 物理层
# osi五层协议
应用层 -- 在两个应用能够通信的基础上又封装了一些应用独有的关系内容 http协议 https协议 ftp协议
传输层(四层) -- 端口 UDP TCP 四层交换机 四层路由器
网络层(三层) -- ipv4 ipv6协议 路由器 三层交换机
数据链路层(二层) -- mac arp协议 网卡 (二层)交换机
物理层 -- 将上述内容进行转换在网线上进行数据的传输
arp协议: 地址解析 通过一台机器的ip地址找到mac地址
TCP三次握手,四次挥手
什么是异步非阻塞?
同步join input 异步 : terminate
阻塞不占用cpu 非阻塞 :占用cpu
同步阻塞 : name = input() ;pwd = input()
同步非阻塞 : say();say2()
异步阻塞 : 比如启动多线程和多个客户端进行tcp通信
可以同时和多个人通信,但是每个人的通信中recv仍然会发生阻塞
异步非阻塞 : 可以启动多线程 设置setblocking(False)
可以同时和多个人通信,并且在过程中没有阻塞
进程,协程,线程
1. 进程,协程,线程的区别:三个都可以提高并发
进程是计算机中资源分配的最小单位,线程是计算机中cpu可调度的最小单位:
协程 又称为 '微线程' 是基于认为创造的,而进程和线程是真是存在的,一个进程可以有多个线程,一个线程可以创建多个协程
2. 计算密集型------使用多进程
3. IO密集型-------使用多线程/协程+IO切换
4. 单纯的协程是没有办法提高并发的,只是代码之间的来回切换,加上 IO 自动切换才有意思,有IO操作使用协程
tcp/udp,粘包
tcp 面向连接 传输可靠 速度慢 能传递的数据长度不限(文件传输)
udp 面向报文 可靠性差 速度快 能传递的数据长度有限(视频流)
什么是黏包?
tcp协议数据无边界的特点 导致了多条分散发送的数据粘合在一起变成了一条数据
第一次消息太大,另一端一次只能接收部分内容
解决方法:struct模块可以将一个类型转成固定长度的bytes
GIL
GIL,全局解释器锁(python特有)
如果没有GIL锁就可以使用多线程,更节省资源
在Python中因为有GIL锁,他同一时刻保证一个进程中只有一个线程可以被cpu调度,所以在使用Python开发时要注意:
(爬虫)计算密集型(想利用多核优势),用多进程.
(输入输出)IO密集型(无法利用多核),用多线程.
线程安全
线程安全(列表/logging模块) - 多个线程去操作同一个数据,不能出现数据的混乱
线程不安全(自己做的文件操作/同事修改一个数字)
使用锁来保证数据安全,来了多个线程,使用锁让他们排队,逐一执行
创建一个线程
创建一个线程
import threading
num = 0
lock = threading.Lock()实例化一个锁对象 --互斥锁-死锁(锁两次,锁里再有锁) (不好的功能,类似于厕所里不能再厕所)
def task():
global num
lock.acquire() # 给这段代码上锁 可以用with lock:
num += 1
lock.release() # 给这段代码解锁
for i in range(10): --多线程
t = threading.Thread(target=task)
t.start()
递归锁 lock = threading.Rlock() 尽量使用Rlock 支持上多次锁
创建一个进程
创建一个进程
from multiprocessing import Process
def a(name):
print(name)
if __name__ == '__main__':
p = Process(target=a,args=("张三",))
p.start() # 开启进程
线程池
线程池
ThreadPoolExecutor:限制开启线程的数量
from concurrent.futures import ThreadPoolExecutor
import time
import random
def a(num):
print(num)
time.sleep(random.randint(1,4))
if __name__ == '__main__':
t = ThreadPoolExecutor(5) # 默认为cpu核心*5
for i in range(20):
t.submit(a,1)
进程池
进程池
ProcessPoolExecutor:限制开启进程的数量
创建进程池的类:如果指定numprocess为3,则进程池会创建三个进程,然后自始至终 使用这三个进程去执行所有任务,不会开启其他进程
优点:
提高操作系统效率
减少空间的占用等
from concurrent.futures import ProcessPoolExecutor
import time
import random
def a(num):
print(num)
time.sleep(random.randint(1,4))
if __name__ == '__main__':
p = ProcessPoolExecutor(5) # 默认为cpu核心数
for i in range(20):
p.submit(a,1)
守护线程setDaemon
守护线程setDaemon 等待其他非守护线程和主线程结束后结束,如果守护进程的生命周期小于其他线程则先结束
import threading
import time
def task(arg):
time.sleep(5)
print('任务')
t = threading.Thread(target=task,args=(11,))
t.setDaemon=True
t.start()
print('END')
守护进程daemon
守护进程daemon 设置为守护进程的子进程,会在主进程结束后马上结束,设置守护进程需要在开启进程前设置
from multiprocessing import Process
import time
def a():
time.sleep(1)
print("子")
if __name__ == '__main__':
p = Process(target=a)
p.daemon = True
p.start()
print("主")
基于线程锁完成一个单例模式
单例模式为什么要加锁
因为在多线程去创建的实例过程中,可能会存在多个线程都通过了最开始的判断,每一次都去创建新的对象了
import threading
import time
class Singleton单例:
instance = None
lock = threading.RLock()
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
if cls.instance:
return cls.instance
with cls.lock:
if cls.instance:
return cls.instance
time.sleep(0.1)
cls.instance = object.__new__(cls)
return cls.instance
def task():
obj = Singleton('x')
print(obj)
for i in range(10):
t = threading.Thread(target=task)
t.start()
# 执行1000行代码
data = Singleton('asdfasdf')
print(data)
面向对象的上下文管理
含有__enter__和__exit__方法的对象就是上下文管理器。
class FOO():
def __init__(self):
print('实例化一个对象')
def __enter__(self):
print('进入')
def__exit__(self,exc_type,exc_val,exc_tb)
print('退出')
obj = F00()
with obj:
print('正在执行')
三,数据库
mysql
mysql 行级锁与表级锁
begin; 开启事务
select * from app01_author where id=1 for update; #加行级锁
commit; 结束事务
django用的时候
from django.db import transaction
def func():
with transaction.atomic():
queryset = models.Customer.objects.filter(pk__in=pk_list).select_for_update()行级锁
queryset.update(你的操作)
行级锁 :只对涉及到修改的行加锁,利于并发的修改,但是对于一次性大量修改效率低下
表级锁 :一次性加一把锁就锁住了整张表,不利于并发的修改,但是加锁速度比行锁的效率要高
mysql索引
索引(目录)为了方便查找涉及的一个机制
主键索引
唯一索引
普通索引
联合主键
联合唯一
联合普通
操作索引 :创建和删除
创建 :create index 索引名 on 表名(字段名);
create index ind_id on s1(id);
删除 :drop index 索引名 on 表名;
正确的使用索引(******)
1.只有对创建了索引的列进行条件筛选的时候效率才能提高
2.索引对应的列做条件不能参与运算、不能使用函数
3.当某一列的区分度非常小(重复率高),不适合创建索引
4.当范围作为条件的时候,查询结果的范围越大越慢,越小越快
5.like关键字 : 如果使用%/_开头都无法命中索引
6.多个条件 : 如果只有一部分创建了索引,条件用and相连,那么可以提高查询效率
# 如果用or相连,不能提高查询效率
引擎
InnoDB 是mysql的默认引擎,支持可靠的事务处理。
修改 SET default_storage_engine=< 存储引擎名 >
什么是存储引擎:存储方式,存储机制
存储引擎的种类: basdasb
myisam - 5.5版本,5.4版本 默认的引擎 ,索引和数据和表结构是分开存的
支持- 1表级锁 2数据的持久化存储
innoDb - 索引和数据是存在一起的,表结构是单寸的
支持- 1.数据的持久化存储
2.事物:一致性,n条语句的执行状态是一致的,要么都成功,要么都失败!
3.行级锁:只对涉及到修改的行加锁,利于并发的修改,但是对于一次性做大量修改效率低下
4.表级锁:一次性加一把锁就锁住了整张表,不利于并发的修改,但是加锁速度比行级锁效率要高
5.外键约束:被约束表中的数据不能随意的修改/删除 约束字段的数据要根据被约束的表,来使用数据
memory - 基于 哈希,查找速度快,存储在内存当中,对于零时的表是有用的,只存表结构
特点 - 数据断电消失 -不支持持久化存储 存在内存中
优化方案
读写分离
分库分表
用定长字段代替变长字段
添加索引,尽量加在区分度高的,数量小的列上
数据库四大特性
数据库事务transanction正确执行的四个基本要素。ACID,原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)。
原子性: 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
一致性:一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
隔离性: 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
持久性:是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
事物
事务的隔离级别
1.未提交读(READ UNCOMMITED) 解决的障碍:无; 引入的问题:脏读
set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
2.已提交读 (READ COMMITED) 解决的障碍:脏读; 引入的问题:不可重复读
set SESSION TRANSACTION ISOLATION LEVEL read committed;
3.可重复读(REPEATABLE READ)解决的障碍:不可重复读; 引入的问题:幻读
set SESSION TRANSACTION ISOLATION LEVEL repeatable read;
4.可串行化(SERIALIZABLE)解决的障碍:可重复读; 引入的问题:锁全表,性能低下
set SESSION TRANSACTION ISOLATION LEVEL repeatable read;
脏读幻读
脏读
脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
**幻读**(Phantom Reads)
原因:事务A根据相同条件第二次查询到事务B提交的新增数据,两次数据结果集不一致。不符合事务的隔离性。
幻读和脏读有点类似
脏读是事务B里面修改了数据,
幻读是事务B里面新增了
索引原理 B+树 聚集索引和辅助索引
索引原理
磁盘预读性原理:一个block快/9ms 1个block = 4096个字节,磁盘预读性原理 :每一次都磁盘都是有单位的,一次最少读取1block块
索引的两种存储方式
聚集索引/聚簇索引(只能创建一个) :innodb的主键才会有聚集索引 -- 叶子节点会存储整行数据
辅助索引/非聚集索引(可以创建无数个) :除了主键之外的普通索引都是辅助索引,一个索引没办法查到整行数据,需要回聚集索引再查一次(回表)
优缺点:
# 优点 :加快查询速度
# 缺点 :降低写的效率 ,占用更多的磁盘空间
balance tree -- b树(平衡树)
balance tree -- b树(平衡树)
1.数据存储在分支节点和叶子节点上(导致了树的高度增加,找到一个数据的时间不稳定)
2.在查找范围的时候不够便捷
b+树 (是为了更好的处理范围问题在b树的基础上有所优化,叶子和叶子节点之间再加上一个双向指针,方便范围查询)
mysql中innodb存储引擎的所有索引树都是b+树
1.数据不再存储在分支节点了,而是存储在叶子节点上(树的高度降低,找到所有数据的时间稳定)
2.在叶子节点与叶子节点之间添加的双向指针提高了在查找范围的效率
基本操作
2.基础操作
1.数据库(文件夹)的操作
创建数据库
create database 数据库名;
查看所有的库
show databases;
切换到对应库中/进入对应的文件夹
use 数据库名;
查看当前所在的库
select database();
2.表(文件)的操作
创建表
create table 表名(列名 数据类型 约束条件);
查看有哪些表
show tables;
查看表结构
desc 表名;
describe 表名;
3.数据的操作
写数据
insert into 表名 values(2,'alex','sb123');
查看表
select * from 表名
数据的修改
update 表名 set 数据的=修改 where 条件
数据的删除
delete from 表名 where 条件
4.数据类型
数字类型
整数 tinyint(255) int
小数 float double
unsigned 无标点符号 约束用的
字符串
char(字符)255 定长,节省时间,浪费空间
varchar(字符)65535 变长,节省空间,浪费时间
时间类型
now() 函数表示当前时间
datetime 年月日时分秒 0000-9999
date 年月日
time 时分秒
year 年
timestamp 年月日时分秒 1970-2038
enum 和set
enum 单选
set 多选 自动去重
1.单表查询
-
select 列查询
select * from 表; *代表所有的列
-
指定列查询
select 列1,列2 from 表;
-
在列中使用四则运算
select 列1,列2*12 from 表;
-
重命名
select 列1,列2 as annl_列2 from 表; select 列1,列2 annl_列2 from 表; 加不加as都可以
-
去重
select distinct 列 from 表; select distinct 列1,列2 from 表; 可以去重多个列
-
-
函数 concat() 拼接
select concat('姓名:',列名1),concat('年薪;',列名2) from 表; select concat_ws('|','a','b','c')
7.case when语句 == if条件判断句
2.where语句 根据条件进行筛选行
1. 比较运算符 = > < >= <= !=/<>
select * from 表 where age > 18;
-
between a and b #[a,b] 区间
select * from 表 where salary between 10000 and 20000;
-
in
select * from 表 where age in(18,20);
-
like 模糊查询
-
_通配符 表示一个字符长度的任意内容
select * from 表 where name like '赵_'
-
% 通配符 表示任意字符长度的任意内容
select * from 表 where name like '赵%' select * from 表 where name like '%赵%'
-
regexp 正则匹配 有模糊查询,正则就用的很少
select * from employee where emp_name regexp '^jin'
-
-
-
5.逻辑运算
and
select * from 表 where age >18 and post = 'teacher';
or
select * from 表 where age<30 or age>20;
not
select * from 表 where age not in (15,18,20);
6. 关于null
# 查看岗位描述为NULL的员工信息
# select * from employee where post_comment is null;
# 查看岗位描述不为NULL的员工信息
# select * from employee where post_comment is not null;
7.五个聚合函数
# count 统计
# max 最大值
# min 最小值
# avg 平均值
# sum 求和
8.分组聚合 group by
select * from 表 where 条件 group by 分组
例;
# 查询岗位名以及岗位包含的所有员工名字
# select post,group_concat(emp_name) from employee group by post;
# 查询各部门年龄在20岁以上的人的平均薪资
# select post,avg(salary) from employee where age>20 group by post;
9.过滤 having (group by + 聚合函数)
例子
# 查询平均薪资大于1w的部门
# select avg(salary) from employee group by post having avg(salary) > 10000
# 1. 查询各岗位内包含的员工个数小于2的岗位名、岗位内包含员工名字、个数
# select post,emp_name,count(id) from employee group by post having count(id)<2
# 2. 查询各岗位平均薪资大于10000的岗位名、平均工资
# select post,avg(salary) from employee group by post having avg(salary) > 10000
# 3. 查询各岗位平均薪资大于10000且小于20000的岗位名、平均工资
# select post,avg(salary) from employee group by post having avg(salary) between 10000 and 20000;
-
order by 排序
# 升序
# select * from employee order by 排序的列名;
# select * from employee order by 排序的列名asc;
# 降序
# select * from employee order by salary desc;
# select * from employee order by age,salary;
# select * from employee order by age,salary desc;
# select * from employee order by age desc,salary;
-
limit
select * from sc limit 1 # 第一条
select * from sc limit 0,30 # 前30条
# select * from 表 order by 列 limit n; 取前n条
# select * from 表 order by 列 limit m,n; 从m+1开始,取n条
# select * from 表 order by 列 limit n offset m; 从m+1开始,取n条
-
select * from 表 where 条件 group by 分组 having 过滤 order by 排序 limit n;
-
编码问题
# 编码问题
# 1.临时解决问题 在客户端执行 set xxxx = utf8;
# 2.永久解决问题 在my.ini添加 set xxxx = utf8;
# 3.实时解决问题 create table 表名() charset=utf8;
2.多表查询
连表
方式一
笛卡尔积
内连接(所有不在条件匹配内的数据,都会被剔除连表)
select * from 表1,表2 where 数据1 = 数据2;
例如:select * from employee,department where dep_id = department.i;
方式二
inner join
select * from 表1 inner join 表2 on 数据1 = 数据2;
例如:select * from employee inner join department on dep_id = department.id;
外连接
左外连接 left join
左边表为主表,副表数据如果无法对应主表,会通过null补齐
select * from 表1 left join 表2 on 数据1 = 数据2;
例如:select * from employee left join department on dep_id = department.id;
右外连接 right join
右边表为主表,副表数据如果无法对应主表,会通过null补齐
select * from 表1 right join 表2 on 数据1 = 数据2;
例如:select * from employee right join department on dep_id = department.id;
union 全外连接
表与表都连接 数据都会有
select * from 表1 union 表2 on 数据1 = 数据2;
1.约束
-
非空 not null
create table 表1(字段1 int not null,name char(12)); 不写默认插入0 create table 表1(字段1 int .name char(12) not null); 默认插入空字符串
-
default 默认值
create table 表1(id int,name char(12),sex enum('男','女)default '男')
非空 和默认
create table 表1(id int not null ,name char(12) not null,sex enum('男','女') not null default '男');
-
-
唯一约束 unique(不能重复)
create table 表1(id int unique,name char(12 unique);
联合唯一约束(不能同名同姓)
create table t5(姓 char(12),名 char(12),unique(姓,名));
唯一 + 非空 id name
唯一加非空 第一个被设置了非空+唯一约束会被定义为主键 primary key
create table t6 (id int not null unique ,name char(12) not null unique);
-
主键(primary key) 唯一性 不能有重复 比如 id =1 不能再重复
# create table t6(id int primary key, name char(12) not null unique); # create table t5(family char(12) ,name char(12),primary key(family,name)); # 约束各自不能为空 且联合唯一 还占用了整张表的主键
-
unsigned 无标点符号 约束用的
-
自增 auto_increment
单独不可以 必须加上唯一或者主键 才会自增
# delete from t7; 清空表数据但不能重置auto_increment # truncate table t7; # 清空表并且重置auto_increment # create table t9(id int unique auto_increment, name char(12)) auto_increment=100000; ==>指定自增从10000开始 # 修改auto_increment # alter table 表名 auto_increment = n; 修改表的auto_increment # alter table t7 auto_increment = 1000; 修改表的auto_increment
6.外键:foreign key
一、主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。
外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键。
创建
foreign key(class_id) references class2(cid)); 关联(references)
# create table class2(cid int unique,cname char(12)); 表id 必须是唯一的
# create table stu2(id int,name char(12),class_id int,foreign key(class_id) references class2(cid));
7.级联更新
foreign key(class_id) references class3(cid) on update cascade);
stu3 class3 级联更新
# create table class3(cid int primary key,cname char(12));
# create table stu3(id int,name char(12),class_id int,foreign key(class_id) references class3(cid) on update cascade);
# insert into class3 values(1,'py27');
# insert into stu3 values (1,'日魔',1),(2,'炮手',1)
# update class3 set cid = 2; 修改了class3中的cid,stu3中相关的数据也会跟着变化,是on update(更新如果换成delete 就是级联删除) cascade关联字设置导致的
redis
redis使用场景
1)Session共享(单点登录)
2)页面缓存
3)队列
4)排行榜/计数器
5)发布/订阅
针对各种数据类型它们的特性,使用场景如下:
字符串string: 用于保存一些项目中的普通数据,只要键值对的都可以保存,例如,保存 session,定时记录状态
哈希hash:用于保存项目中的一些字典数据,但是不能保存多维的字典,例如,商城的购物车
列表list:用于保存项目中的列表数据,但是也不能保存多维的列表,例如,队列,秒杀,医院的挂号
无序集合set:用于保存项目中的一些不能重复的数据,可以用于过滤,例如,投票海选的时候,过滤候选人
有序集合zset:用于保存项目中一些不能重复,但是需要进行排序的数据,分数排行榜.
使用Redis的优势
1.速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
2. 支持丰富数据类型,支持string,list,set,sorted set,hash
3.支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
4.丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
redis哨兵、集群、主从复制、持久化
1.redis主从:是备份关系, 我们操作主库,数据也会同步到从库。
2. redis哨兵:哨兵保证的是HA,保证特殊情况故障自动切换,哨兵盯着你的“redis主从集群”,如果主库死了,它会告诉你新的老大是谁
3.redis集群:集群保证的是高并发,因为多了一些兄弟帮忙一起扛。同时集群会导致数据的分散,整个redis集群会分成一堆数据槽,即不同的key会放到不不同的槽中
4.redis 支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另一种是 Append-only file(缩写 aof)的方式。
Redis哨兵主要功能
(1)集群监控:负责监控Redis master和slave进程是否正常工作
(2)消息通知:如果某个Redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
(3)故障转移:如果master node挂掉了,会自动转移到slave node上
(4)配置中心:如果故障转移发生了,通知client客户端新的master地址
Redis 主从复制、哨兵和集群这三个有什么区别
1.主从模式:读写分离,备份,一个Master可以有多个Slaves。
2.哨兵sentinel:监控,自动转移,哨兵发现主服务器挂了后,就会从slave中重新选举一个主服务器。
3.集群:为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/QPS不受限于单机,可受益于分布式集群高扩展性。
四,Django
restful规范
RESTful规范锁一套接口的协议,用于程序与程序见数据交换的一套默认规则
RESTful规范规定了以下几点:
- https代替http,保证数据传输时安全。
- 在url中一般要体现api标识
- 在接口中要体现版本
- restful也称为面向资源编程,一般资源都使用名词
- 筛选条件要添加在url中
- 根据method不同做不同操作
- 返回状态码
- 返回值
- 增加数据时返回新增的数据
- 单条查询返回字典
- 多条查询返回列表
- 更新返回更新后的完整数据
- 删除返回空
- 操作异常时,要返回错误信息
- 返回下一个请求的接口
示例:
http://www.takanashi.com/api/v1/user/?page=1
Django请求生命周期的概念
从用户输入url到用户看到网页的整个过程。
请求过程描述
(1)用户输入网址,浏览器发起请求
(2)WSGI(服务器网关接口)创建socket服务端,接受请求
(3)中间件处理请求
(4)url路由,根据当前请求的url找到相应的视图函数
(5)进入view,进行业务处理,执行类或者函数,返回字符串
(6)再次通过中间件处理响应
(7)WSGI返回响应
(8)浏览器渲染
drf如何帮助我们快速开发的?drf提供了那些功能?
- 视图,APIView用处还不知道。
- 解析器,根据用户请求体格式不同进行数据解析,解析之后放在request.data中。 在进行解析时候,drf会读取http请求头 content-type. 如果content-type:x-www-urlencoded,那么drf会根据 & 符号分割的形式去处理请 求体。 user=wang&age=19 如果content-type:application/json,那么drf会根据 json 形式去处理请求体。 {"user":"wang","age":19}
- 序列化,可以对QuerySet进行序列化,也可以对用户提交的数据进行校验。
- 渲染器,可以帮我们把json数据渲染到页面上进行友好的展示。(内部会根据请求设备不同做不同的 展示)
状态码
返回给用户状态码
- 200,成功
- 300,301永久 /302临时
- 400,403拒绝 /404找不到
- 500,服务端代码错误
drf 继承顺序
class View(object):
class APIView(View):
class GenericAPIView(APIView):
class ListAPIView(ListModelMixin,GenericAPIView):
自定义类 一层一层网上找
接口是对数据操作增删改查 使用listAPIview
接口不对数据库操作比如短信验证,评论,这些继承APIview就行了
Session
Session:记录一系列状态
Session与cookie功能效果相同。Session与Cookie的区别在于Session是记录在服务端的,而Cookie是记录在客户端的
session
HTTP协议是无状态,每次请求之间都相互独立的,之间没有关系,没办法保存状态。
定义:
保存在服务器上的一组组键值对,必须依赖cookie
为什么要有?
cookie保存在浏览器上,不太安全
浏览器对cookie的大小有一定的限制
浏览器发送请求,没有cookie也没有session
要设置session时,先根据浏览器生成一个唯一标识(session_key),存键值对,并且有超时时间
返回cookie session_id = 唯一标识
中间件
中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件负责做一些特定的功能。
中间件的五种方法
中间件 :中间件就是一个类,在全局范围内处理django的请求和响应。
类 5个方法 4个特点
规律:
#在你视图函数之前执行的这些方法按照顺序执行,
#在视图函数执行之后的这些方法按照倒序执行
-------------------------------------------------------------------------
process_request(self,request)
执行时间:
在视图函数之前
执行顺序:
按照注册的顺序 顺序执行
参数 :
request: 请求的对象,和视图函数是同一个
返回值:
None : 正常流程
HttpResponse:之后中间件的process_request、路由、process_view、视图都不执行,执行执行当前中间件对应process_response方法,接着倒序执行之前的中间件中的process_response方法。
中间件--> 浏览器发送请求回复响应,之前是在视图里回复响应的,写到中间件里会响应,后面要做的事就不用做了!
-------------------------------------------------------------------------
process_response(self, request, response)
执行时间:
在视图函数之后
执行顺序:
按照注册的顺序 倒序执行
参数 :
request: 请求的对象,和视图函数是同一个
response: 响应对象
返回值:
HttpResponse: 必须返回
返回值可以是别人传过来的response
也可以自己返回 HttpResponse
-------------------------------------------------------------------------
process_view(self, request, view_func, view_args, view_kwargs)
执行时间:
在路由匹配之后,在视图函数之前
执行顺序:
按照注册的顺序 顺序执行
参数 :
request: 请求的对象,和视图函数是同一个
view_func:视图函数
view_args: 给视图传递的位置参数
view_kwargs: 给视图传递的关键字参数
返回值:
None: 正常流程
HttpResponse: 之后中间件的process_view、视图都不执行,直接执行最后一个中间件process_response,倒序执行之前中间件的process_response方法
-------------------------------------------------------------------------
process_exception(self, request, exception)
执行时间:
在视图函数出错之后执行
执行顺序:
按照注册的顺序 倒序执行
参数 :
request: 请求的对象,和视图函数是同一个
exception:报错的对象
返回值:
None: 自己没有处理,交给下一个中间件处理,所有的中间件都没有处理,django处理错误。
HttpResponse: 之后中间件的process_exception,直接执行最后一个中间件process_response,倒序执行之前中间件的process_response方法
-------------------------------------------------------------------------
process_template_response(self,request,response)
执行时间:
当视图函数返回一个TemplateResponse对象
执行顺序:
按照注册的顺序 倒序执行
参数 :
request: 请求的对象,和视图函数是同一个
response:响应的对象
返回值:
HttpResponse: 必须返回
MVC
.MVC和MTV
MVC
M: model 模型 数据库交互
V:view 视图 展示给用户看的 HTML
C :controller 控制器 业务逻辑 传递指令
MTV:
M: model 模型 ORM
T: template 模板
V: view 视图 业务逻辑
五,Linux
Linux 常用命令
ls 命令,展示文件夹内内容
cd 命令
tree命令,显示树形的层级目录结构,非原生命令,需要安装tree
cp 命令,作用复制
rm命令作用为删除,参数
mv命令作用为移动文件
pwd命令,作用为查看”当前工作目录“的完整路径
tar命令,用于压缩解压
mkdir命令创建目录
rmdir 命令删除目录
进程相关命
查看进程
ps aux 或者 ps -ef #查看机器所有进程信息
ps aux | grep "vim" #过滤出和vim有关的进程
ps 命令显示运行的进程,还会显示进程的一些信息如pid, cpu和内存使用情况等
kill 命令用于终止进程
killall 命令和参数
top 命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况
权限相关命令
chmod命令:
chown命令改变文件所有者:
chgrp命令,改变文件所属组
useradd 命令建立用户账号
usermod 修改用户信息
userdel 删除用户
passwd 设置用户的密码
vim文本查看编辑等命令
打开文件
vim 文件名
q 退出
q! 修改数据后,不保存数据强制退出
wq! 保存数据后退出
w filename 将文件保存到另一个文件中
复制,粘贴,删除
yy: 复制当前行
#yy :复制当前往下#行
p :当前光标下粘贴
delete: 删除当前光标所在的单个字符
dd :删除(剪切)当前行
#dd :删除(剪切)当前光标往下到#
查看端口是否占用
语法如下
常用的参数组合 -t -n -u -l -p
[root@s25linux tmp]# netstat -tunlp #显示机器所有的tcp、udp的所有端口连接情况
#例如验证服务器80端口是否存在
netstat -tunlp | grep 80
Linux查看系统资源占用
(1) free命令默认是以kb为单位显示的,可以用free -m 用Mb单位来显示。
(2) Mem行 : total = used + free 其中buffers和cached虽然计算在used内, 但其实为可用内存。
(3) Mem下一行:used为真实已占内存,free为真实可用内存。
(4)Swap:内存交换区的使用情况。
常用命令
ifconfig 查看ip地址
rm -f 删除
cd 目录切换
ls 目录下有什么内容
pwd 能够输出当前所在的绝对路径
touch 创建一个普通文本文件
mkdir 创建一个文件夹
tree 以树状图显示文件目录的层级结构
echo 命令如同python的print一样,能够输出字符串到屏幕给用户看
which python #输出命令所在的绝对路径
cp 拷贝
mv 移动文件 重命名
find 搜索
ls -lh -h参数,是显示文件单位,以kb mb gb大小为单位 -l是列表形式,列出文件夹中详细信息
grep 过滤有用信息的命令
scp 通过网络安全的传输文件,文件夹
进程相关
ps ps -ef # -ef,是一个组合参数,-e -f 的缩写,默认显示 linux所有的进程信息,以及pid,时间,进程名等 信息
top 能够显示 动态的进程信息
kill 杀死进程的命令 -9强制
netstat -tunlp | grep 80 验证服务器80端口是否存在
六,算法
•<>冒泡排序<>
◾将乱序列表中的最大值逐步找出,将最大值最终移动到最后的位置
<>选择排序<>改进了冒泡排序,每次遍历列表只做一次交换。为了做到这一点,一个选择排序在他遍历时寻找最大的值,并在完成遍历后,将其放置在正确的位置。
<>•插入排序:将列表假设分成两部分,第一部分为列表的第一个元素(有序序列),剩下的元素(无序序列),以此将无序序列中的元素逐一插入到有序序列的合适位置
- 希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本,该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量(gap)”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率比直接插入排序有较大提高。
-快速排序-将列表中第一个元素设定为基准数字,赋值给mid变量,然后将整个列表中比基准小的数值放在基准的左侧,比基准到的数字放在基准右侧。然后将基准数字左右两侧的序列在根据此方法进行排放。
七,git码云版本控制
版本控制
git init 初始化仓库
git init 文件 创建文件并初始化仓库
git status 查看状态
git add 文件名 /. 将变化的内容添加到暂存区
git commit -m '描述信息' 提交到版本库
git push -u origin 分支 远程仓库地址
git log 查看版本记录
git reflog 查看版本变更记录
git reset --hard 版本号 版本回退
git clone 拉取代码