django缓存机制 |
在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面.
当一个网站的用户访问量很大的时候,每一次的的后台操作,都会消耗很多的服务端资源,所以必须使用缓存来减轻后端服务器的压力.
缓存是将一些常用的数据保存内存或者memcache中,在一定的时间内有人来访问这些数据时,则不再去执行数据库及渲染等操作,而是直接从内存或memcache的缓存中去取得数据,然后返回给用户.
django中的6中缓存方式
开发调试缓存 没有缓存
内存缓存
文件缓存
数据库缓存
缓存到redis
Memcache缓存(使用python-memcache模块)
Memcache缓存(使用pylibmc模块)
经常使用的有文件缓存和Mencache缓存
缓存配置
settings中配置缓存位置的配置(settings中配置,BACKEND不同,缓存的位置不同) 必须要配置
CACHES = {
'default':{
'BACKEND':'django.core.cache.backends.filebased.FileBasedCache', #指定缓存使用的引擎
'LOCATION':'E:\huancun_redis', #指定缓存的路径
'TIMEOUT':300, #缓存超时时间(默认为300秒,None表示永不过期)
'OPTIONS':{
'MAX_ENTRIES':300, #最大缓存记录的数量(默认300)
'CULL_FREQUENCY':3, #缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
} }
}
缓存粒度
全站缓存
单页面缓存
局部缓存
文件缓存(把缓存数据存储在文件中)
使用:
settings文件,把cache配置进去
单页面缓存:在视图函数上加一个装饰器
from django.views.decorators.cache import cache_page @cache_page(5) 5 代表缓存时间
例子
fbv加局部缓存装饰器
import time
from django.views.decorators.cache import cache_page 局部缓存装饰器
# #局部缓存
@cache_page(5)
def index(request):
ctime = time.time()
return render(request,'index.html',{'ctime':ctime})
cbv加装饰器
from django.utils.decorators import method_decorator
django的bug,不能直接对类进行装饰,必须使用 method_decorator,把装饰器当作参数传进去。
@method_decorator(wrapper, name="post")
#PS:CBV中添加装饰器 def wrapper(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner
#1.指定方法上添加装饰器 class Foo(View): @method_decorator(wrapper) def get(self,request): pass def post(self,request): pass
#2.在类上添加 @method_decorator(wrapper,name='dispatch') class Foo(View): def get(self,request):
pass def post(self,request): pass
局部缓存
{% load cache %} {% cache 5 'test'} <!--第一个参数表示缓存时间,第二个参数是key值(取缓存的时候,需要根据key值取)--> 当前时间:{{ ctime }}
{% endcache %}
视图函数
from django.views.decorators.cache import cache_page
import time
from .models import *
def index(request):
cttime=time.time() #获取当前时间
bookList=Book.objects.all()
return render(request,"index.html",locals())
全站缓存
既然是全站缓存,当然要使用Django中的中间件.
用户的请求通过中间件,经过一系列的认证等操作,如果请求的内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户
当返回给用户之前,判断缓存中是否已经存在,如果不存在,则UpdateCacheMiddleware会将缓存保存至Django的缓存之中,以实现全站缓存
#缓存整个站点,是最简单的缓存方法
#在MIDDLEWARE_CLASSES 中加入 "update"和"fetch"中间件 MIDDLEWARE_CLASSES = (
‘django.middleware.cache.UpdateCacheMiddleware’, #第一
'django.middleware.common.CommonMiddleware',
‘django.middleware.cache.FetchFromCacheMiddleware’, #最后
) #"update"必须配置在第一个
#"fetch" 必须配置在最后一个
需要改settings.py配置文件
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware', #全局控制 内部有process_response 响应HTTPResponse中设置几个headers
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware' #全局控制 内部有process_request 用来缓存通过GET和HEAD方法获取的状态码为200的响应
] CACHE_MIDDLEWARE_SECONDS=5 #去局配置缓存 过期时间
视图函数
import time def index(request):
ctime = time.time()
return render(request,'index.html',{'time':ctime})
模板
{{ time }}
其余代码不变,刷新浏览器5秒,页面上的时间变化一次,这样就实现了全站缓存
高级用法
前后端分离项目
from django.core.cache import cache
cache.set cache.get
设置值跟取值:
cache.set('test_data',{'name':'lqz','age':18},5)
cache.get('test_data')
自定义Response对response再次进行封装
from rest_framework.response import Response class MyResponse():
def __init__(self):
self.code = 100
self.msg = None def get_response(self):
return Response(self.__dict__) #返回名称空间
使用
from app01.utils import MyResponse #自定义Response封装
from rest_framework.views import APIView
class Test(APIView):
def get(self,request):
response = MyResponse()
response.data = {'name':'llxbl','age':18}
response.code = 200
response.msg = '查询成功'
return response.get_response()
开发调试(此模式为开发调试使用,实例上不执行任何操作)
settings配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 缓存后台使用的引擎
'TIMEOUT': 300, # 缓存超时时间(默认300秒,None表示永不过期,0表示立即过期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
}
}
第二种
# 此为开始调试用,实际内部不做任何操作
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎
'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存个数(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
'KEY_PREFIX': '', # 缓存key的前缀(默认空)
'VERSION': 1, # 缓存key的版本(默认1)
'KEY_FUNCTION': 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
}
} # 自定义key
def default_key_func(key, key_prefix, version):
"""
Default function to generate keys. Constructs the key used by all other methods. By default it prepends
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
function with custom key making behavior.
"""
return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func):
"""
Function to decide which key function to use. Defaults to ``default_key_func``.
"""
if key_func is not None:
if callable(key_func):
return key_func
else:
return import_string(key_func)
return default_key_func
内存缓存(将缓存内容保存至内存区域中)
settings配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 指定缓存使用的引擎
'LOCATION': 'unique-snowflake', # 写在内存中的变量的唯一值
'TIMEOUT':300, # 缓存超时时间(默认为300秒,None表示永不过期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
}
}
}
数据库缓存(把缓存数据存储在数据库中)
settings配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache', # 指定缓存使用的引擎
'LOCATION': 'cache_table', # 数据库表
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
}
}
}
# 注创建缓存的数据库表使用的语句:执行创建表命令 python manage.py createcachetable
Memcache缓存(使用python-memcached模块连接memcache)
Memcached是Django原生支持的缓存系统.要使用Memcached,需要下载Memcached的支持库python-memcached或pylibmc.
settings.py文件配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', # 指定缓存使用的引擎
'LOCATION': '192.168.10.100:11211', # 指定Memcache缓存服务器的IP地址和端口
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
}
}
}
LOCATION也可以配置成如下:
'LOCATION': 'unix:/tmp/memcached.sock', # 指定局域网内的主机名加socket套接字为Memcache缓存服务器
'LOCATION': [ # 指定一台或多台其他主机ip地址加端口为Memcache缓存服务器
'192.168.10.100:11211',
'192.168.10.101:11211',
'192.168.10.102:11211',
]
第二种
# 此缓存使用python-memcached模块连接memcache CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
# 设置权重,memcache模块做的
('172.19.26.240:11211',1)
('172.19.26.242:11211',10)
]
}
}
Memcache缓存(使用pylibmc模块连接Memcache)
settings.py文件配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', # 指定缓存使用的引擎
'LOCATION':'192.168.10.100:11211', # 指定本机的11211端口为Memcache缓存服务器
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
}
}
LOCATION也可以配置成如下:
'LOCATION': '/tmp/memcached.sock', # 指定某个路径为缓存目录
'LOCATION': [ # 分布式缓存,在多台服务器上运行Memcached进程,程序会把多台服务器当作一个单独的缓存,而不会在每台服务器上复制缓存值
'192.168.10.100:11211',
'192.168.10.101:11211',
'192.168.10.102:11211',
]
Memcached是基于内存的缓存,数据存储在内存中.所以如果服务器死机的话,数据就会丢失,所以Memcached一般与其他缓存配合使用
第二种
# 此缓存使用pylibmc模块连接memcache CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
跨域问题(同源策略) |
浏览器的:同源策略,浏览器拒绝不是当前域返回的数据
ip地址和端口号都相同才是同一个域
比如:我在本地上的域名是127.0.0.1:8000,请求另外一个域名:127.0.0.1:8001一段数据
浏览器上就会报错,个就是同源策略的保护,如果浏览器对javascript没有同源策略的保护,那么一些重要的机密网站将会很危险
已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8001/SendAjax/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
但是注意,项目2中的访问已经发生了,说明是浏览器对非同源请求返回的结果做了拦截
如何解决:
CORS:跨域资源共享
简单请求:发一次请求
非简单请求:非简单请求是发送了两次请求,第一次是预检请求(OPTIONS请求),当预检通过,允许我发请求,再发送真实的请求
简单请求需要满足两大条件
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
* 简单请求和非简单请求的区别? 简单请求:一次请求
非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。
* 关于“预检” - 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何“预检”
=> 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
Access-Control-Request-Method
=> 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
Access-Control-Request-Headers
支持跨域,简单请求
服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'
支持跨域,复杂请求
由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。
- “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
- “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
$('button').click(function () {
alert('111');
$.ajax({
url:'http://127.0.0.1:8001/index/',
type:'post',
contentType:'application/json',
data:{'name':'lqz'},
success:function (data) {
console.log(data)
}
})
})
被请求站点
def index(request): obj = HttpResponse('')
if request.method == 'OPTIONS':
# #允许它
obj['Access-Control-Allow-Headers']='Content-Type'
# # obj['Access-Control-Allow-Headers'] = '*'
#
#
# # obj['Access-Control-Allow-Origin'] = '*'
obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
print(obj)
return obj
解决跨域问题:(写好一个中间件配置一下) 被请求站点
from django.utils.deprecation import MiddlewareMixin class MyCorsMiddle(MiddlewareMixin):
def process_response(self, request, response):
if request.method == 'OPTIONS':
#允许它
response['Access-Control-Allow-Headers'] = 'Content-type'
#response['Access-Control-Allow-Headers'] = '*' # response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
# 允许的请求站点
response['Access-Control-Allow-Origin'] = '*'
return response
MIDDLEWARE = [
'app01.MyMiddle.MyCorsMiddle', #跨域问题
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]