Django中的缓存方式
缓存位置:
缓存到内存中
缓存到数据库中,(一条语句查询出多条数据)
缓存到文件
缓存到redis
缓存位置的配置(在setting中配置,BACKEND不同,缓存的位置不同)
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', # 指定缓存使用的引擎
'LOCATION': 'D:\lqz\cache', # 指定缓存的路径
'TIMEOUT': 300, # 缓存超时时间(默认为300秒,None表示永不过期)
'OPTIONS': {
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
}
}
}
缓存粒度:
全站缓存注:全站缓存是根据你的路由来区分缓存的位置的
需要以下配置:
settings.py 需要你在通过所有的中间件的校验,然后才能去缓存中取出数据,然后依次返回,返回到中间件的最初然后更新数据(若没有数据到数据库查找数据,更新数据)
settings.py
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'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'
]
CACHE_MIDDLEWARE_SECONDS = 2
单页面缓存
注:单页面缓存是根据你的路由来区分缓存的位置的
from django.views.decorators.cache import cache_page
@cache_page(5)
def index(request):
ctime = time.time()
return render(request,'index.html',{"ctime":ctime})
局部缓存
{% load cache %}
{% cache 5 "test" %}
<h1>{{ ctime }}</h1>
{% endcache %}
高级用法前后端分离:
代码如下:
from django.core.cache import cache
from rest_framework.views import APIView
from rest_framework.response import Response
class Test(APIView):
def get(self,request,*args,**kwargs):
cache.set('test_data',{"name":"wy","age":18},3)
#若取出来为空说明你超时了
time.sleep(2)
x = cache.get("test_data")
if x:
print('未超时')
back_dic = {
"stat":"未超时"
}
return Response(back_dic)
else:
print("超时")
back_dic = {
"stat": "超时"
}
return Response(back_dic)
跨域问题:
-浏览器的:同源策略,浏览器拒绝不是当前域域返回的数据,因为请求了一个资源发现不是我同源的会担心是病毒,所以浏览器不接受,只有你通过CORS跨域资源共享才可以。
-ip地址和端口号都相同才是同一个域
-如何解决:
-CORS:跨域资源共享
-简单请求:发一次请求
-非简单请求:非简单请求是发送了两次请求,第一次是预检请求(OPTIONS请求),当预检通过,允许我发请求,再发送真实的请求。
由于不管你是post还是get请求只要是非简单请求你都需要发送OPTIONS,这样每条非简单的请求都需要发送OPTIONS,我们可以在全局中做了这件事,通过中间件的process_response,为什么是response因为是需要返回给你的浏览器端,是最后返回,然后你需要判断是不是OPTIONS请求,是的化你就设置允许,只要头部加了Content-Type你就需要设置允许:response[“Access-Control-Allow-Headers”] = “Content-Type”,如果不是你还需要设置:response[“Access-Control-Allow-Origin”] = “http://127.0.0.1:8000”
最后返回response对象。
from django.contrib.sessions.middleware import SessionMiddleware
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-Origin"] = "http://127.0.0.1:8000"
return response
具体案例:
访问端代码:
urls.py:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
]
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt,name="dispatch")
# Create your views here.
def index(request):
# if request.method==''
return render(request,'index.html')
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<button id="btn">点我</button>
</body>
<script>
$("#btn").click(function () {
$.ajax({
url:'http://127.0.0.1:8080/books/'
,type:"post",
contentType:"application/json",
success:function (res) {
console.log(res)
}
})
})
</script>
</html>
另外一端:中间件装饰
from django.contrib.sessions.middleware import SessionMiddleware
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class MyMiddle(MiddlewareMixin):
def process_response(self, request, response):
if request.method == 'OPTIONS':
# 请求返回返回头中
response['Access-Control-Allow-Headers'] = 'Content-Type'
dat = request.META
# print(dat)
orgin = dat.get("HTTP_ORIGIN")
l = []
ip, port = orgin.rsplit(":", 1)
l.append(port)
if port in ['8002','8003','8004']:
print(ip, port)
response['Access-Control-Allow-Origin'] = orgin
# response['Access-Control-Allow-Origin'] = "http://127.0.0.1:8001"
print(type(response),response)
return response
序列化
MySer.py
from rest_framework import serializers
from app01 import models
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
from django.shortcuts import render,HttpResponse
# Create your views here.
from rest_framework.views import APIView
from app01.MySer import BookSer
from app01 import models
from rest_framework.response import Response
# from rest_framework.viewsets import ModelViewSet
class Book(APIView):
#
def get(self,request,*args,**kwargs):
print('xxxxxx')
book_list = models.Book.objects.all()
bookser = BookSer(instance=book_list,many=True)
back_dic = {"code":100}
back_dic['data'] = bookser.data
return HttpResponse("yy")
def post(self,request,*args,**kwargs):
print('post')
book_list = models.Book.objects.all()
bookser = BookSer(instance=book_list,many=True)
back_dic = {"code":100}
back_dic['data'] = bookser.data
return HttpResponse("zz")
token应用:
客户端登录成功后,服务器根据客户端的信息制作一个唯一的token值传给浏览器,浏览器下次来访问的时候带着这个token,然后服务端通过自己的算法将token解出来与用户的签名匹配,匹配成功则表示用户是合法用户.
在你项目目录下新建一个用于校验是否登陆过的代码认证代码MyAuth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.views import APIView
from rest_framework.exceptions import AuthenticationFailed
from app01 import models
from django.core.cache import cache
from django.core.cache import cache
class Auth(BaseAuthentication):
def authenticate(self, request):
'''
首先接收那个头中的数据,接收浏览器端头部的数据都是通过请求request.META.get("HTTP_传入的名字")
'''
#传了一个token过来
print(request.META)
#获取前端传过来的头信息中的token
token_get = request.META.get("HTTP_TOKEN")
#从缓存取出数据token数据,cache(key,value,过期时间)
token = cache.get(token_get)
#下方是为了给数据库减压使用的,由于使用缓存中的数据可以减少数据库的访问,若缓存过期了再去数据库中查找。
if not token:#缓存中没有token,然后就到数据库张找
token_obj = models.Token.objects.filter(token=token_get)
if token_obj:
#反向查询表明小写
print('超时了')
return token_obj.first().user,token_get
else:
# print('用户名或者密码错误')
raise AuthenticationFailed("用户名或者密码错误")
# return False,False
else:
print('没有超时')
token_obj = models.Token.objects.filter(token=token_get)
return token_obj.first().user, token
视图函数:
from rest_framework.views import APIView
from app01.MyAuth import Auth
import time
import hashlib,pickle
# from
'''
-4 全站缓存
-在setting中配置两个中间件:注意顺序
'django.middleware.cache.UpdateCacheMiddleware',
。。。。
'django.middleware.cache.FetchFromCacheMiddleware'
'''
from django.core.cache import cache
from app01 import models
def token_produce(v1):
'''
:param v1: 用户名
'''
#token是由名字与我的时间组合而成的
md = hashlib.md5()
md.update(v1.encode("utf-8"))
return md.hexdigest()
from app01 import MySer
from rest_framework.response import Response
#token 超时时间 与缓存的超时时间
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
#CBV的csrf装饰器,之呢给加在类上,指定dispatch分发方法相当于给所有的都解除了中间件的校验。
@method_decorator(csrf_exempt,name="dispatch")
class Login(APIView):
def post(self,request,*args,**kwargs):
print('post')
name = request.data.get("name")
password = request.data.get("password")
user_obj = models.User.objects.filter(name=name,password=password).first()
print(name,password)
if user_obj:
token_str = token_produce(name)
# va = user_obj.token
# print("*(**(*(",va,type(va))
models.Token.objects.update_or_create(token=token_str)
# print(token)
# tokenser = MySer.TokenSer(instance=token)
back_dic = {'token':token_str}
cache.set(token_str,token_str,600)
return Response(back_dic)
else:
return Response("登录失败")
class Book(APIView):
#图书类,首先要通过验证才能查看图书,因此加了身份认证
authentication_classes = [Auth, ]
def get(self,request,*args,**kwargs):
print('book')
book_list = models.Book.objects.all()
#序列化主要是为了前端的交互方便,序列化为json,而我的HttpResponse不能序列化queryset对象。
book_ser = MySer.BookSer(instance=book_list,many=True)
return Response(book_ser.data)
Myser.py序列化
from rest_framework import serializers
from app01 import models
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
class TokenSer(serializers.ModelSerializer):
class Meta:
model = models.Token
fields = "__all__"
models.py类:
from django.db import models
# Create your models here.
class User(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=32)
token = models.OneToOneField(to="Token")
class Token(models.Model):
token = models.CharField(max_length=256)
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)