赞
踩
目录
Python和Java、PHP、C、C#、C++等其他语言的对比?
Python3和Python2中 int 和 long的区别?
文件操作时:xreadlines和readlines的区别?
求结果: a. [ i % 2 for i in range(10) ] b. ( i % 2 for i in range(10) )
求结果: a. 1 or 2 b. 1 and 2 c. 1 < (2==2) d. 1 < 2 == 2
如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?
比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?
如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ?
列举面向对象中带爽下划线的特殊方法,如:__new__、__init__
json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?
json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?
什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?
如果redis中的某个列表中的数据量非常大,如果实现循环显示每一个值?
MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?
写代码,基于redis的列表实现 先进先出、后进先出队列、优先级队列。
如何基于redis实现发布和订阅?以及发布订阅和消息队列的区别?
列举django中间件的5个方法?以及django中间件的应用场景?
列举django orm 中所有的方法(QuerySet对象的所有方法)
select_related和prefetch_related的区别?
django的Form组件中,如果字段中包含choices参数,请使用两种方式实现数据源实时更新。
django的Model中的ForeignKey字段中的on_delete参数有什么作用?
基于django使用ajax发送post请求时,都可以使用哪种方法携带csrf token?
django中如何实现orm表中添加数据时创建一条日志记录。
django的模板中filter和simple_tag的区别?
解释orm中 db first 和 code first的含义?
为什么要使用django rest framework框架?
django rest framework框架中都有那些组件?
django rest framework框架中的视图都可以继承哪些类?
简述 django rest framework框架的认证流程。
django rest framework如何实现的用户访问频率控制?
Flask中上下文管理主要涉及到了那些相关的类?并描述类主要作用?
为什么要Flask把Local对象中的的值stack 维护成一个列表?
解释Flask框架中的Local对象和threading.local对象的区别?
SQLAlchemy中的 session和scoped_session 的区别?
Tornado中静态文件是如何处理的? 如:
RabbitMQ如何在消费者获取任务后未处理完前就挂掉时,保证数据不丢失?
以下RabbitMQ的exchange type分别代表什么意思?如:fanout、direct、topic。
celery中装饰器 @app.task 和 @shared_task的区别?
简述 saltstack、ansible、fabric、puppet工具的作用?
二进制转换成十进制:v = “0b1111011”
十进制转换成二进制:v = 18
八进制转换成十进制:v = “011”
十进制转换成八进制:v = 30
十六进制转换成十进制:v = “0x12”
十进制转换成十六进制:v = 87
Python中,主要通过引用计数进行垃圾回收;通过 “标记-清除” 解决容器对象可能产生的循环引用问题;通过 “分代回收” 以空间换时间的方法提高垃圾回收效率。
引用计数
在Python中每一个对象的核心就是一个结构体PyObject,它的内部有一个引用计数器(ob_refcnt)。
程序在运行的过程中会实时的更新 ob_refcnt 的值,来反映引用当前对象的名称数量。当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。
但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。
#filter 返回True或者False,从而留下True的元素
import randomallNum = []
for i in range(9):
allNum.append(random.randint(1,20))
print(allNum)
print(list(filter(lambda x:x%3,allNum)))#输出:
#[8, 8, 9, 5, 4, 11, 19, 12, 1]#[8, 8, 5, 4, 11, 19, 1]
#map 求一个序列或者多个序列进行函数映射之后的值
x=[1,2,3,4] y=[3,4,6,8,8] print(list(map(lambda x,y:(x*y)+2,x,y))) #输出:[5, 10, 20, 34]#reduce 对一个序列进行压缩运算,得到一个值
from functools import reduce x=[3,4,6,8,8] def fun(x,y): return x+y print(reduce(fun,x)) #输出:29
class Stack(object): def __init__(self): self.stack = [] def push(self, value): # 进栈 self.stack.append(value) def pop(self): #出栈 if self.stack: self.stack.pop() else: raise LookupError('stack is empty!') def is_empty(self): # 如果栈为空 return bool(self.stack) def top(self): #取出目前stack中最新的元素 return self.stack[-1]
任何实现了
__iter__
和__next__()
方法的对象都是迭代器class Fib(): def __init__(self,max): self.n = 0 self.prev = 0 self.curr = 1 self.max = max def __iter__(self): return self def __next__(self): if self.n < self.max: value = self.curr self.curr += self.prev self.prev = value self.n += 1 return value else: raise StopIteration # 调用 f = Fib(5) print(next(f)) print(next(f)) print(next(f)) print(next(f)) print(next(f))生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写
__iter__()
和__next__()
方法了,只需要一个yiled
关键字。 生成器一定是迭代器def fib(max): n, prev, curr = 0, 0, 1 while n<max: yield curr prev, curr = curr, curr + prev n += 1
- def BinarySearch(nums:list,x:int) -> int:
- '''
- nums: Sorted array from smallest to largest
- x: Target number
- '''
- left,right = 0,len(nums)-1
- while left <= right:
- mid = (left+right)//2
- if nums[mid] == x:
- return mid
- if nums[mid] < x:
- left = mid+1
- else:
- right = mid-1
- return None
闭包可以理解成“定义在一个函数内部的函数“
实例方法
定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
调用:只能由实例对象调用。
类方法
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:类和实例对象都可以调用。
静态方法
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:类和实例对象都可以调用。
yield from是返回另外一个生成器
三次握手过程理解
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
四次挥手过程理解
1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
详见武沛齐博客:https://www.cnblogs.com/wupeiqi/articles/5729934.html
select * from tb where name = ‘Oldboy-Wupeiqi’
select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1
1、redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。
2、通过redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力。主数据库主要进行写操作,而从数据库负责读操作。
全量同步过程:
1:当一个从数据库启动时,会向主数据库发送sync命令,
2:主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并用缓存区记录后续的所有写操作
3:当主服务器快照保存完成后,redis会将快照文件发送给从数据库。
4:从数据库收到快照文件后,会丢弃所有旧数据,载入收到的快照。
5: 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令。
6: 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令。
增量同步的过程:
Redis增量复制是指slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
有2**14个哈希槽 16384个
LRU(最近少用的淘汰)
即redis的缓存每命中一次,就给命中的缓存增加一定ttl(过期时间)(根据具体情况来设定, 比如10分钟).一段时间后, 热数据的ttl都会较大, 不会自动失效, 而冷数据基本上过了设定的ttl就马上失效了.
先进lpush keys values 先出 rpop keys
先进lpush keys values 后出 lpop keys
Redis中五大数据结构之一—列表,其PUSH和POP命令遵循FIFO先进先出原则。当我们需要发布消息的时候执行LPUSH(消息从左边进入队列),消息接收端执行RPOP获得消息(消息从右侧弹出)。对于列表,Redis提供了带有阻塞的命令(命令前加B)。因此,生产者lpush消息,消费者brpop(从列表中弹出最右端元素,如无元素则一直阻塞到timeout)消息,并设定超时时间timeout,可以减少redis的压力。
创建一个频道 客户端加入频道 等待频道发布订阅
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.
redis对事务的支持还比较简单,redis只能保证一个client发起的事务中的命令可以连续执行,而中间不会插入其他client的命令。当一个client在一个连接中发出multi命令时,这个连接会进入一个事务的上下文,连接后续命令不会立即执行,而是先放到一个队列中,当执行exec命令时,redis会顺序的执行队列中的所有命令。
>multi //开启一个事务
>set age 10 //暂存指令队列
>set age 20
>exec //开始执行(提交事务)或
>discard //清空指令队列(事务回滚)
Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
5)String
set(key, value):给数据库中名称为key的string赋予值value
get(key):返回数据库中名称为key的string的value
getset(key, value):给名称为key的string赋予上一次的value
mget(key1, key2,…, key N):返回库中多个string的value
setnx(key, value):添加string,名称为key,值为value
setex(key, time, value):向库中添加string,设定过期时间time
mset(key N, value N):批量设置多个string的值
msetnx(key N, value N):如果所有名称为key i的string都不存在
incr(key):名称为key的string增1操作
incrby(key, integer):名称为key的string增加integer
decr(key):名称为key的string减1操作
decrby(key, integer):名称为key的string减少integer
append(key, value):名称为key的string的值附加value
substr(key, start, end):返回名称为key的string的value的子串6)List
rpush(key, value):在名称为key的list尾添加一个值为value的元素
lpush(key, value):在名称为key的list头添加一个值为value的 元素
llen(key):返回名称为key的list的长度
lrange(key, start, end):返回名称为key的list中start至end之间的元素
ltrim(key, start, end):截取名称为key的list
lindex(key, index):返回名称为key的list中index位置的元素
lset(key, index, value):给名称为key的list中index位置的元素赋值
lrem(key, count, value):删除count个key的list中值为value的元素
lpop(key):返回并删除名称为key的list中的首元素
rpop(key):返回并删除名称为key的list中的尾元素
blpop(key1, key2,… key N, timeout):lpop命令的block版本。
brpop(key1, key2,… key N, timeout):rpop的block版本。
rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部7)Set
sadd(key, member):向名称为key的set中添加元素member
srem(key, member) :删除名称为key的set中的元素member
spop(key) :随机返回并删除名称为key的set中一个元素
smove(srckey, dstkey, member) :移到集合元素
scard(key) :返回名称为key的set的基数
sismember(key, member) :member是否是名称为key的set的元素
sinter(key1, key2,…key N) :求交集
sinterstore(dstkey, (keys)) :求交集并将交集保存到dstkey的集合
sunion(key1, (keys)) :求并集
sunionstore(dstkey, (keys)) :求并集并将并集保存到dstkey的集合
sdiff(key1, (keys)) :求差集
sdiffstore(dstkey, (keys)) :求差集并将差集保存到dstkey的集合
smembers(key) :返回名称为key的set的所有元素
srandmember(key) :随机返回名称为key的set的一个元素8)Hash
hset(key, field, value):向名称为key的hash中添加元素field
hget(key, field):返回名称为key的hash中field对应的value
hmget(key, (fields)):返回名称为key的hash中field i对应的value
hmset(key, (fields)):向名称为key的hash中添加元素field
hincrby(key, field, integer):将名称为key的hash中field的value增加integer
hexists(key, field):名称为key的hash中是否存在键为field的域
hdel(key, field):删除名称为key的hash中键为field的域
hlen(key):返回名称为key的hash中元素个数
hkeys(key):返回名称为key的hash中所有键
hvals(key):返回名称为key的hash中所有键对应的value
hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value
一、获取到的所有Redis的实例数必须大于N/2,即至少有N/2 + 1个实例
二、获取所有Redis实例的时间 + 时钟漂移 + 业务执行时间应该小于TTL
。
另外需要注意的是:
1、一定要为每个Redis实例设置超时时间,且这个时间要远小于TTL
,以避免获取某个Redis的锁时长时间阻塞,而影响整个流程。
2、在释放Redis的分布式锁时要释放所有实例,即使没有获取到该实例。
3、重试机制应该设置一定的次数限制分布式锁一般有三种实现方式:
- 基于数据库
在数据库中创建一张表,表里包含方法名等字段,并且在方法名字段上面创建唯一索引,执行某个方法需要使用此方法名向表中插入数据,成功插入则获取锁,执行结束则删除对应的行数据释放锁- 基于缓存数据库Redis
Redis性能好并且实现方便,但是单节点的分布式锁在故障迁移时产生安全问题,Redlock是Redis的作者 Antirez 提出的集群模式分布式锁,基于N个完全独立的Redis节点实现分布式锁的高可用- 基于ZooKeeper
ZooKeeper 是以 Paxos 算法为基础的分布式应用程序协调服务,为分布式应用提供一致性服务的开源组件// 获取锁 unique_value作为唯一性的校验 SET resource_name unique_value NX PX 30000 // 释放锁 比较unique_value是否相等 避免误释放 if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
基本单位为chunk,chunk中包含数条doc记录.chunk默认大小是64M,写满后就生成新的chunk
1、查询所有记录:db.userInfo.find(); 相当于:select* from userInfo;:默认每页显示20条记录,当显示不下的情况下,可以用it迭代命令查询下一页数据。注意:键入it命令不能带“;”但是你可以设置每页显示数据的大小,用DBQuery.shellBatchSize= 50;这样每页就显示50条记录了。2、查询去掉后的当前聚集集合中的某列的重复数据:db.userInfo.distinct("name"); 会过滤掉name中的相同数据 相当于:select distict name from userInfo;3、按照年龄排序:升序:db.userInfo.find().sort({age: 1}); 降序:db.userInfo.find().sort({age: -1});4、查询name = zhangsan, age = 22的数据 db.userInfo.find({name: 'zhangsan', age: 22}); 相当于:select * from userInfo where name = ‘zhangsan’ and age = ‘22’;5、查询前5条数据:db.userInfo.find().limit(5); 相当于:selecttop 5 * from userInfo;6、创建索引:db.userInfo.ensureIndex({name: 1});7、查询当前聚集集合所有索引:db.userInfo.getIndexes();8、添加:db.users.save({name: ‘zhangsan’, age: 25, sex: true}); 添加的数据的数据列,没有固定,根据添加的数据为准9、修改:db.users.update({age: 25}, {$set: {name: 'changeName'}}, false, true); 相当于:update users set name = ‘changeName’ where age = 25;10、删除:db.users.remove({age: 132});11、创建一个聚集集合(table):db.createCollection(“collName”, {size: 20, capped: 5, max: 100});
12、得到指定名称的聚集集合(table): db.getCollection("account");
WebSocket是应用层协议
WebSocket是基于TCP的应用层协议,用于在C/S架构的应用中实现双向通信,关于WebSocket协议的详细规范和定义参见rfc6455。
需要特别注意的是:虽然WebSocket协议在建立连接时会使用HTTP协议,但这并意味着WebSocket协议是基于HTTP协议实现的。WebSocket与Http的区别:
1.通信方式不同
WebSocket是双向通信模式,客户端与服务器之间只有在握手阶段是使用HTTP协议的“请求-响应”模式交互,而一旦连接建立之后的通信则使用双向模式交互,不论是客户端还是服务端都可以随时将数据发送给对方;而HTTP协议则至始至终都采用“请求-响应”模式进行通信。也正因为如此,HTTP协议的通信效率没有WebSocket高。2.协议格式不同
WebSocket与HTTP的协议格式是完全不同的,具体来讲:
(1)HTTP协议(参见:rfc2616)比较臃肿,而WebSocket协议比较轻量。
(2)对于HTTP协议来讲,一个数据包就是一条完整的消息;而WebSocket客户端与服务端通信的最小单位是帧(frame),由1个或多个帧组成一条完整的消息(message)。即:发送端将消息切割成多个帧,并发送给服务端;服务端接收消息帧,并将关联的帧重新组装成完整的消息。相比起HTTP协议,WebSocket具备如下特点:
- 支持双向通信,实时性更强。
- 更好的二进制支持。
- 较少的控制开销:连接创建后,WebSockete客户端、服务端进行数据交换时,协议控制的数据包头部较小。
- 支持扩展。
1、OPTIONS
返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性
2、HEAD
向服务器索与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。
3、GET
向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中,例如在Web Application中,其中一个原因是GET可能会被网络蜘蛛等随意访问。Loadrunner中对应get请求函数:web_link和web_url
4、POST
向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 Loadrunner中对应POST请求函数:web_submit_data,web_submit_form
5、PUT
向指定资源位置上传其最新内容
6、DELETE
请求服务器删除Request-URL所标识的资源
7、TRACE
回显服务器收到的请求,主要用于测试或诊断
8、CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
注意:
1)方法名称是区分大小写的,当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Mothod Not Allowed);当服务器不认识或者不支持对应的请求方法时,应返回状态码501(Not Implemented)。
2)HTTP服务器至少应该实现GET和HEAD/POST方法,其他方法都是可选的,此外除上述方法,特定的HTTP服务器支持扩展自定义的方法。
200 OK 当您的操作将在响应正文中返回数据时,出现此结果。
204 No Content 当您的操作成功,但不在响应正文中返回数据时,出现此结果。
304 Not Modified(重定向) 当测试实体自上次检索以来是否被修改时,出现此结果。
403 Forbidden 客户端错误
401 Unauthorized 客户端错误
413 Payload Too Large(客户端错误) 当请求长度过长时,出现此结果。
400 BadRequest(客户端错误) 当参数无效时,出现此结果。
404 Not Found(客户端错误) 当资源不存在时,出现此结果。
405 Method Not Allowed(客户端错误)由于方法和资源组合不正确而出现此错误。 例如,您不能对一个实体集合使用 DELETE 或 PATCH。
412 Precondition Failed 客户端错误
501 Not Implemented(服务器错误) 当未实施某个请求的操作时,出现此结果。
503 Service Unavailable(服务器错误) 当 Web API 服务不可用时,出现此结果。
Django 与 Tornado 各自的优缺点
Django
优点:大和全(重量级框架)
自带orm,template,view
需要的功能也可以去找第三方的app
注重高效开发
全自动化的管理后台(只需要使用起ORM,做简单的定义,就能自动生成数据库结构,全功能的管理后台)
session功能
缺点:template不怎么好用(来自自身的缺点)
数据库用nosql不方便(来自自身的缺点)
如果功能不多,容易臃肿Tornado
优点:少而精(轻量级框架)
注重性能优越,速度快
解决高并发(请求处理是基于回调的非阻塞调用)
异步非阻塞
websockets 长连接
内嵌了HTTP服务器
单线程的异步网络程序,默认启动时根据CPU数量运行多个实例;利用CPU多核的优势
自定义模块
缺点:模板和数据库部分有很多第三方的模块可供选择,这样不利于封装为一个功能模块
总结:
要性能, Tornado 首选;要开发速度,Django 和 Flask 都行,区别是 Flask 把许多功能交给第三方库去完成了,因此 Flask 更为灵活。
全称Python Web Server Gateway Interface,指定了web服务器和Python web应用或web框架之间的标准接口,以提高web应用在一系列web服务器间的移植性。 具体可查看 官方文档
从以上介绍我们可以看出:
- WSGI是一套接口标准协议/规范;
- 通信(作用)区间是Web服务器和Python Web应用程序之间;
- 目的是制定标准,以保证不同Web服务器可以和不同的Python程序之间相互通信
1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端 请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post,体现在url之中.
2. url经过Django中的wsgi,再经过Django的中间件,最后url到过路由映射表,在路由中一条一条进行匹配, 一旦其中一条匹配成功就执行对应的视图函数,后面的路由就不再继续匹配了.
3. 视图函数根据客户端的请求查询相应的数据.返回给Django,然后Django把客户端想要的数据做为一个字符串返回给客户端.
4. 客户端浏览器接收到返回的数据,经过渲染后显示给用户.
一个url对应一个视图函数,这个模式叫做FBV(
Function Base Views
)除了FBV之处,Django中还有另外一种模式叫做CBV(
Class Base views
),即一个url对应一个类 由dispatch返回
请求走到WSGIHandler类的时候,执行cell方法,将environ封装成了request
1,直接在类上加装饰器
@method_decorator(test,name=‘dispatch’)
class Loginview(view)
2,直接在处理的函数前加装饰器
@method_decorator(test)
def post(self,request,*args,**kwargs):
pass
all() 查询所有结果 filter(**kwargs) 它包含了与所给筛选条件相匹配的对象。获取不到返回None get(**kwargs) 返回与所给筛选条件相匹配的对象,返回结果有且只有一个。获取不到会抱胸 #如果符合筛选条件的对象超过一个或者没有都会抛出错误 exclude(**kwargs) 它包含了与所给筛选条件不匹配的对象 order_by(*field) 对查询结果排序 reverse() 对查询结果反向排序 count() 返回数据库中匹配查询(QuerySet)的对象数量 first() 返回第一条记录 last() 返回最后一条记录 exists() 如果QuerySet包含数据,就返回True,否则返回False values(*field) 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系 model的实例化对象,而是一个可迭代的字典序列 values_list(*field) 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 distinct() 从返回结果中剔除重复纪录
defer('id','name'):取出对象,字段除了id和name都有
only('id','name'):取的对象,只有id和name
- select_related主要针一对一和多对一关系进行优化。
- select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
- 可以通过可变长参数指定需要select_related的字段名。也可以通过使用双下划线“__”连接字段名来实现指定的递归查询。没有指定的字段不会缓存,没有指定的深度不会缓存,如果要访问的话Django会再次进行SQL查询。
- 也可以通过depth参数指定递归的深度,Django会自动缓存指定深度内所有的字段。如果要访问指定深度外的字段,Django会再次进行SQL查询。
- 也接受无参数的调用,Django会尽可能深的递归查询所有的字段。但注意有Django递归的限制和性能的浪费。
- Django >= 1.7,链式调用的select_related相当于使用可变长参数。Django < 1.7,链式调用会导致前边的select_related失效,只保留最后一个。
- 对于多对多字段(ManyToManyField)和一对多(ForeignKey)字段,可以使用prefetch_related()来进行优化.
- 因为select_related()总是在单次SQL查询中解决问题,而prefetch_related()会对每个相关表进行SQL查询,因此select_related()的效率通常比后者高。
- 鉴于第一条,尽可能的用select_related()解决问题。只有在select_related()不能解决问题的时候再去想prefetch_related()。
- 你可以在一个QuerySet中同时使用select_related()和prefetch_related(),从而减少SQL查询的次数。
- 只有prefetch_related()之前的select_related()是有效的,之后的将会被无视掉。
(一)手动读写分离
1. 在使用数据库时,通过.using(db_name)来手动指定要使用的数据库
优点:不需要进行其余的配置,只需要通过.using(db_name)来手动指定要使用的数据库就行。
缺点:在大量的对数据库进行操作之后,此种方法繁琐(二)自动读写分离
通过配置数据库路由,来自动实现,这样就不需要每次读写都手动指定数据库了。数据库路由中提供了四个方法。这里这里主要用其中的两个:def db_for_read()决定读操作的数据库,def db_for_write()决定写操作的数据库。
CSRF是什么
跨站请求伪造(CSRF)与跨站请求脚本正好相反。跨站请求脚本的问题在于,客户端信任服务器端发送的数据。跨站请求伪造的问题在于,服务器信任来自客户端的数据。
1)启用中间件
2)post请求
3)验证码
4)表单中添加{% csrf_token%}标签#第一步:django第一次响应来自某个客户端的请求时,后端随机产生一个token值,把这个token保存在SESSION状态中;同时,后端把这个token放到cookie中交给前端页面;
#第二步:下次前端需要发起请求(比如发帖)的时候把这个token值加入到请求数据或者头信息中,一起传给后端;Cookies:{csrftoken:xxxxx}
#第三步:后端校验前端请求带过来的token和SESSION里的token是否一致;
#1.后端将csrftoken传到前端,发送post请求时携带这个值发送
data: {
csrfmiddlewaretoken: '{{ csrf_token }}'
},
#2.获取form中隐藏标签的csrftoken值,加入到请求数据中传给后端
data: {
csrfmiddlewaretoken:$('[name="csrfmiddlewaretoken"]').val()
},
#3.cookie中存在csrftoken,将csrftoken值放到请求头中
headers:{ "X-CSRFtoken":$.cookie("csrftoken")}
使用django的信号机制,可以在添加、删除数据前后设置日志记录
pre_init # Django中的model对象执行其构造方法前,自动触发
post_init # Django中的model对象执行其构造方法后,自动触发
pre_save # Django中的model对象保存前,自动触发
post_save # Django中的model对象保存后,自动触发
pre_delete # Django中的model对象删除前,自动触发
post_delete # Django中的model对象删除后,自动触发
- jango中提供了6种缓存方式:
- 开发调试(不加缓存)
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
-
- 安装第三方组件支持redis:
- django-redis组件
-
-
- 设置缓存
- # 全站缓存(中间件)
- MIDDLEWARE_CLASSES = (
- ‘django.middleware.cache.UpdateCacheMiddleware’, #第一
- 'django.middleware.common.CommonMiddleware',
- ‘django.middleware.cache.FetchFromCacheMiddleware’, #最后
- )
-
- # 视图缓存
- from django.views.decorators.cache import cache_page
- import time
-
- @cache_page(15) #超时时间为15秒
- def index(request):
- t=time.time() #获取当前时间
- return render(request,"index.html",locals())
-
- # 模板缓存
- {% load cache %}
- <h3 style="color: green">不缓存:-----{{ t }}</h3>
-
- {% cache 2 'name' %} # 存的key
- <h3>缓存:-----:{{ t }}</h3>
- {% endcache %}
django的缓存能使用redis吗?如果可以的话,如何配置?
- pip install django-redis
- apt-get install redis-serv
-
- 在setting添加配置文件
- CACHES = {
- "default": {
- "BACKEND": "django_redis.cache.RedisCache", # 缓存类型
- "LOCATION": "127.0.0.1:6379", # ip端口
- "OPTIONS": {
- "CLIENT_CLASS": "django_redis.client.DefaultClient", #
- "CONNECTION_POOL_KWARGS": {"max_connections": 100} # 连接池最大连接数
- # "PASSWORD": "密码",
- }
- }
- }
-
-
- 使用
- from django.shortcuts import render,HttpResponse
- from django_redis import get_redis_connection
-
- def index(request):
- # 根据名字去连接池中获取连接
- conn = get_redis_connection("default")
- conn.hset('n1','k1','v1') # 存数据
- return HttpResponse('...')
db first: 先创建数据库,再更新表模型
code first:先写表模型,再更新数据库
https://www.cnblogs.com/jassin-du/p/8988897.html
SQL: # 优点: 执行速度快 # 缺点: 编写复杂,开发效率不高
ORM: # 优点: 让用户不再写SQL语句,提高开发效率 可以很方便地引入数据缓存之类的附加功能 # 缺点: 在处理多表联查、where条件复杂查询时,ORM的语法会变得复杂。 没有原生SQL速度快
MVC:model 模型、view(视图)、controller(控制器) MTV:model、tempalte、view
http,默认端口:80 https,默认端口:443
http的数据是基于明文传输。 https的数据是基于密文传输。
lask-wtf组件
flask-login组件
flask-session组件
flask-sqlalchemy组件
flask-script组件
flask-cache组件
flask-assets组件
flask-restful组件
flask-mail组件
flask-openid组件
flask-babel组件
celery工具
MongoEngine工具
将不同的功能模块化
a.一个项目可以具有多个Blueprint
b. 可以将一个Blueprint注册到任何一个未使用的URL下比如 “/”、“/sample”或者子域名
c. 在一个应用中,一个模块可以注册多次
d.Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,它并不是必须要实现应用的视图和函数的
e.在一个应用初始化时,就应该要注册需要使用的Blueprint
构建大型应用
优化项目结构
增强可读性、易于维护
flask-socketio
后端选用了flask-socketio库来实现websocket功能。
初始化
from flask import Flask, render_template
from flask_socketio import SocketIOapp = Flask(__name__)
app.config.from_object("config.{}".format(os.getenv('FLASK_CONFIG') or "dev"))
socketio = SocketIO(app, cors_allowed_origins='*', async_mode='eventlet', engineio_logger=True)if __name__ == '__main__':
socketio.run(app)
原文链接:https://blog.csdn.net/kacylining/article/details/104245137
WTForms 是一个 Python 表单验证、渲染开发包;
使用 WTForms, 你能生成属于你的表单域的 HTML 代码, 此外我们允许你在模板中定 制它. 这允许你维持独立的代码和展现, 并把这些凌乱的参数保留在 Python 代码之外争取松耦合
flask的session是基于cookie的会话保持。简单的原理即:
当客户端进行第一次请求时,客户端的HTTP request(cookie为空)到服务端,服务端创建session,视图函数根据form表单填写session,请求结束时,session内容填写入response的cookie中并返回给客户端,客户端的cookie中便保存了用户的数据。
当同一客户端再次请求时, 客户端的HTTP request中cookie已经携带数据,视图函数根据cookie中值做相应操作(如已经携带用户名和密码就可以直接登陆)。
在 flask 中使用 session 也很简单,只要使用 from flask import session 导入这个变量,在代码中就能直接通过读写它和 session 交互。
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug,它只是工具包,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理。将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。
Flask永远不会包含数据库层,也不会有表单库或是这个方面的其它东西。Flask本身只是Werkzeug和Jinja2的之间的桥梁,前者实现一个合适的WSGI应用,后者处理模板。
下面看一下Flask对象的__init__方法,如果不考虑jinja2相关,核心成员就下面几个:
class Flask: def __init__(self, package_name): self.package_name = package_name self.root_path = _get_package_path(self.package_name) self.view_functions = {} self.error_handlers = {} self.before_request_funcs = [] self.after_request_funcs = [] self.url_map = Map()我们把目光聚集到后面几个成员,view_functions中保存了视图函数(处理用户请求的函数,如上面的hello()),error_handlers中保存了错误处理函数,before_request_funcs和after_request_funcs保存了请求的预处理函数和后处理函数。
self.url_map用以保存URI到视图函数的映射,即保存app.route()这个装饰器的信息,如下所示:
def route(...): def decorator(f): self.add_url_rule(rule, f.__name__, **options) self.view_functions[f.__name__] = f return f return decorator上面说到的是初始化部分,下面看一下执行部分,当我们执行app.run()时,调用堆栈如下:
app.run() run_simple(host, port, self, **options) __call__(self, environ, start_response) wsgi_app(self, environ, start_response)wsgi_app是flask核心:
def wsgi_app(self, environ, start_response): with self.request_context(environ): rv = self.preprocess_request() if rv is None: rv = self.dispatch_request() response = self.make_response(rv) response = self.process_response(response) return response(environ, start_response)可以看到,wsgi_app这个函数的作用就是先调用所有的预处理函数,然后分发请求,再调用所有后处理函数,最后返回response。
看一下dispatch_request函数的实现,因为,这里有flask的错误处理逻辑:
def dispatch_request(self): try: endpoint, values = self.match_request() return self.view_functions[endpoint](**values) except HTTPException, e: handler = self.error_handlers.get(e.code) if handler is None: return e return handler(e) except Exception, e: handler = self.error_handlers.get(500) if self.debug or handler is None: raise return handler(e)如果出现错误,则根据相应的error code,调用不同的错误处理函数。
flask的魔法
如果读者打开flask.py文件,将看到我前面的源码分析几乎已经覆盖了所有重要的代码。但是,细心的读者会看到,在Flask.py文件的末尾处,有以下几行代码:
# context locals _request_ctx_stack = LocalStack() current_app = LocalProxy(lambda: _request_ctx_stack.top.app) request = LocalProxy(lambda: _request_ctx_stack.top.request) session = LocalProxy(lambda: _request_ctx_stack.top.session) g = LocalProxy(lambda: _request_ctx_stack.top.g)这是我们得以方便的使用flask开发的魔法,也是flask源码中的难点。在分析之前,我们先看一下它们的作用。
在flask的开发过程中,我们可以通过如下方式访问url中的参数:
from flask import request @app.route('/') def hello(): name = request.args.get('name', None)看起来request像是一个全局变量,那么,一个全局变量为什么可以在一个多线程环境中随意使用呢,下面就随我来一探究竟吧!
先看一下全局变量_request_ctx_stack的定义:
_request_ctx_stack = LocalStack()
正如它LocalStack()的名字所暗示的那样,_request_ctx_stack是一个栈。显然,一个栈肯定会有push 、pop和top函数,如下所示:
class LocalStack(object): def __init__(self): self._local = Local() def push(self, obj): rv = getattr(self._local, 'stack', None) if rv is None: self._local.stack = rv = [] rv.append(obj) return rv def pop(self): stack = getattr(self._local, 'stack', None) if stack is None: return None elif len(stack) == 1: release_local(self._local) return stack[-1] else: return stack.pop()按照我们的理解,要实现一个栈,那么LocalStack类应该有一个成员变量,是一个list,然后通过 这个list来保存栈的元素。然而,LocalStack并没有一个类型是list的成员变量, LocalStack仅有一个成员变量self._local = Local()。
顺藤摸瓜,我们来到了Werkzeug的源码中,到达了Local类的定义处:
class Local(object): def __init__(self): object.__setattr__(self, '__storage__', {}) object.__setattr__(self, '__ident_func__', get_ident) def __getattr__(self, name): try: return self.__storage__[self.__ident_func__()][name] except KeyError: raise AttributeError(name) def __setattr__(self, name, value): ident = self.__ident_func__() storage = self.__storage__ try: storage[ident][name] = value except KeyError: storage[ident] = {name: value}需要注意的是,Local类有两个成员变量,分别是__storage__和__ident_func__,其中,前者 是一个字典,后者是一个函数。这个函数的含义是,获取当前线程的id(或协程的id)。
此外,我们注意到,Local类自定义了__getattr__和__setattr__这两个方法,也就是说,我们在操作self.local.stack时, 会调用__setattr__和__getattr__方法。
_request_ctx_stack = LocalStack() _request_ctx_stack.push(item) # 注意,这里赋值的时候,会调用__setattr__方法 self._local.stack = rv = [] ==> __setattr__(self, name, value)而__setattr的定义如下:
def __setattr__(self, name, value): ident = self.__ident_func__() storage = self.__storage__ try: storage[ident][name] = value except KeyError: storage[ident] = {name: value}在__setattr__中,通过__ident_func__获取到了一个key,然后进行赋值。自此,我们可以知道, LocalStack是一个全局字典,或者说是一个名字空间。这个名字空间是所有线程共享的。 当我们访问字典中的某个元素的时候,会通过__getattr__进行访问,__getattr__先通过线程id, 找当前这个线程的数据,然后进行访问。
字段的内容如下:
{'thread_id':{'stack':[]}} {'thread_id1':{'stack':[_RequestContext()]}, 'thread_id2':{'stack':[_RequestContext()]}}最后,我们来看一下其他几个全局变量:
current_app = LocalProxy(lambda: _request_ctx_stack.top.app) request = LocalProxy(lambda: _request_ctx_stack.top.request) session = LocalProxy(lambda: _request_ctx_stack.top.session) g = LocalProxy(lambda: _request_ctx_stack.top.g)读者可以自行看一下LocalProxy的源码,LocalProxy仅仅是一个代理(可以想象设计模式中的代理模式)。
通过LocalStack和LocalProxy这样的Python魔法,每个线程访问当前请求中的数据(request, session)时, 都好像都在访问一个全局变量,但是,互相之间又互不影响。
主要是自己面试前抱下佛脚用的,以上。
参考:
不吹不擂,你想要的Python面试都在这里了【315+道题】 - 武沛齐 - 博客园django 框架练习 - 一起奥利给 - 博客园不吹不擂,你想要的Python面试都在这里了【315+道题】 - 武沛齐 - 博客园
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。