Django的边边角角(二):缓存、中间件、分页器、富文本
文章目录
- 一.缓存
- 1.概述
- 2.Django内置缓存实现
- (1)装饰器缓存
- (2)数据库缓存
- (3)内存级数据库缓存(redis)
- 3.多级缓存
- (1)多级缓存 - 装饰器缓存
- (2)多级缓存 - 缓存的基本应用
- (3)多级缓存 - 缓存时间就近原则
- 二.中间件
- 1.介绍
- 2.基本使用
- 3.过滤资源路径
- 4.应用-白名单
- 5.中间件异常
- 6.中间件的执行顺序
- 三.分页器
- 1.原生实现
- 2.封装实现
- 四.富文本
一.缓存
1.概述
目的:
在Django中,当用户请求到达视图后,视图会先从数据库提取数据放到模板中进行动态渲染,渲染后的结果就是用户看到的网页。如果用户每次请求都从数据库提取数据并渲染,将极大降低性能,不仅服务器压力大,而且客户端也无法即时获得响应。如果能将渲染后的结果放到速度更快的缓存中,每次有请求过来,先检查缓存中是否有对应的资源,如果有,直接从缓存中取出来返回响应,节省取数据和渲染的时间,不仅能大大提高系统性能,还能提高用户体验。
应用场景:
缓存主要适用于对页面实时性要求不高的页面。存放在缓存的数据,通常是频繁访问的,而不会经常修改的数据。
我们来举几个应用例子:
博客文章。假设用户一天更新一篇文章,那么可以为博客设置1天的缓存,一天后会刷新。购物网站。商品的描述信息几乎不会变化,而商品的购买数量需要根据用户情况实时更新。我们可以只选择缓存商品描述信息。缓存网页片段。比如缓存网页导航菜单和脚部(Footer)。
2.Django内置缓存实现
(1)装饰器缓存
这是系统封装的,需要注意的是装饰器参数不需要写timeout
创建子路由:
url(r'^testCache/',views.testCache),
生成视图函数:
def testCache(request):time.sleep(5)return HttpResponse('敌军还有5秒抵达战场')
运行结果:
我们会发现每次刷新都需要等待5秒页面才显示。
使用装饰器缓存:
@cache_page(30)
def testCache(request):time.sleep(5)return HttpResponse('敌军还有5秒抵达战场')
我们会发现除了第一次运行是等待5秒后,在30秒内不需要再等待了
(2)数据库缓存
基于数据库,在真实的数据库中去创建缓存表
创建缓存表:
python manage.py createcachetable my_cache_table
创建成功后,我们会发现数据库中有my_cache_table表了
在settings中配置缓存信息:
CACHES={'default':{'BACKEND':'django.core.cache.backends.db.DatabaseCache',#缓存的位置'LOCATION':'my_cache_table',#过期时间'TIMEOUT':60,#前缀'KEY_PREFIX':'python2001',}}
创建子路由:
url(r'^testCache1/',views.testCache1),
生成视图函数:
def testCache1(request):#导入 django.core.cache.cachevalue = cache.get('ip')if value:return HttpResponse(value)else:# ip地址ip = request.META.get('REMOTE_ADDR')cache.set('ip',ip)return HttpResponse('来了老弟')
60秒后,再次刷新:
(3)内存级数据库缓存(redis)
基于redis-内存级数据库
Django-redis-cache使用redis实现django-cache的扩展操作缓存的API没有发生任何变更变更的就是连接缓存的配置
安装 django-redis 和 django-redis-cache:
在settings中配置缓存信息:
CACHES={'default':{'BACKEND':'django_redis.cache.RedisCache',# 缓存的位置# redis一共有16个数据库 0 ~ 15# 6379:redis端口号'LOCATION':'redis://127.0.0.1:6379/1','OPTIONS':{'CLIENT_CLASS':'django_redis.client.DefaultClient'},'KEY_PREFIX': 'django2001',},}
创建子路由:
url(r'^testCache2/',views.testCache2),
生成视图函数:
def testCache2(request):value = cache.get('ip')if value:return HttpResponse('你在缓存中拿到的数据')else:ip = request.META.get('REMOTE_ADDR')cache.set('ip',ip)return HttpResponse('你是从数据库拿的数据')
运行结果:
如果你的redis中报错,端口号已经被占用,那么就是因为你的这个服务已经开启
可以使用ps -ef | grep -i redis 来查看,如果已经开启,不要急于杀死进程
解决策略:将settings中的配置中redis的主机地址设置为127.0.0.1
如果你连接redis的时候出现转圈的情况:
(1)查看云主机的入方向和出方向的端口 必须要开放6379端口
基本端口 22:ssh , 80:http , 443:https , 3306:mysql , 6379:redis , 8000:django的默认端接口
入方向和出方向,必须一致
以下策略基本上在linux操作系统出现的概率不大,如果有按照以下方案来改:
(2)配置文件中不允许远程连接
56行代码是 bind 127.0.0.1 将这行代码注释,因为默认是只允许本地连接
76行代码是protect_model = yes 修改为no
3.多级缓存
写多套配置,定义不同的名字,存入缓存的时候,获取不同的缓存对象,想使用哪个缓存就创建哪个缓存的实例对象
在settings中配置缓存信息:
CACHES = {'default': {'BACKEND': 'django.core.cache.backends.db.DatabaseCache','LOCATION': 'my_cache_table','TIMEOUT': 60 * 5,'KEY_PREFIX':'databaseCache2001',},'django2001': {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://127.0.0.1:6379/1","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient",},'KEY_PREFIX':'redis2001','TIMEOUT': 60 * 5,}
}
创建主路由:
url(r'^final/',include('FinalApp.urls',namespace='final')),
(1)多级缓存 - 装饰器缓存
创建子路由:
url(r'^testCache/',views.testCache),
生成视图函数:
#可以使用装饰器,指定想要的数据库
@cache_page(30,cache='default')
def testCache(request):time.sleep(5)return HttpResponse('欢迎来到英雄联盟')
运行结果:
查看缓存表中也有记录:
(2)多级缓存 - 缓存的基本应用
创建子路由:
url(r'^testCache1/',views.testCache1),
生成视图函数:
def testCache1(request):cache = caches['django2001']value = cache.get('ip')if value:return HttpResponse('有值')else:ip = request.META.get('REMOTE_ADDR')cache.set('ip',ip)return HttpResponse('没值')
第一次运行结果:
第二次运行结果:
查看是否存入redis:
(3)多级缓存 - 缓存时间就近原则
思考:在settings设置了缓存时间’TIMEOUT’: 60 * 5,如果又在装饰器缓存中设置了缓存时间,那么是执行哪个???
创建子路由:
url(r'^testCache2/',views.testCache2),
生成视图函数:
@cache_page(30,cache='django2001')
def testCache2(request):time.sleep(5)return HttpResponse('测试缓存的优先级')
运行结果:
当我们等30s后还没到5分钟的时候,再次刷新页面,会发现我们需要等待5s,所以缓存的时间以视图函数为主,就近原则
二.中间件
1.介绍
中间件:是一个轻量级的,底层的插件,可以介入到Django的请求和响应过程(面向切面编程)
中间件的本质就是一个python类
面向切面编程(Aspect Oriented Programming)简称AOP。AOP的主要实现目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合的隔离效果。
django内置的一个底层插件
从属于面向切面编程AOP
在不修改源代码的情况下,动态去添加一些业务逻辑处理
中间件的典型实现:装饰器
中间件就是使用类装饰实现的
面向切面编程
切点(1)process_requestprocess_request(self,request):在执行视图前被调用,每个请求上都会调用,不主动进行返回或返回HttpResponse对象(2)process_viewprocess_view(self,request,view_func,view_args,view_kwargs):调用视图之前执行,每个请求都会调用,不主动进行返回或返回HttpResponse对象(3)process_template_response process_template_response(self,request,response):在视图刚好执行完后进行调用,每个请求都会调用,不主动进行返回或返回HttpResponse对象(4)process_responseprocess_response(self,request,response):所有响应返回浏览器之前调用,每个请求都会调用,不主动进行返回或返回HttpResponse对象(5)process_exceptionprocess_exception(self,request,exception):当视图抛出异常时调用,不主动进行返回或返回HttpResponse对象
切面切点处切开可以获得的数据
2.基本使用
(1)在工程目录下创建middleware目录
(2)目录中创建一个python文件
(3)在python文件中导入中间件的基类
from django.utils.deprecation import MiddlewareMixin
(4)在类中根据功能需求,创建切入需求类,重写切入点方法:
class TestMiddle(MiddlewareMixin):def process_request(self,request):print('i am first middleware')
(5)启用中间件,在settings中进行配置,MIDDLEWARE中添加: middleware.文件名.类名
创建子路由:
url(r'^testMiddleware/',views.testMiddleware),
生成视图函数:
def testMiddleware(request):return HttpResponse('天道酬勤')
运行结果:
思考:若中间件中有返回值,视图函数中有返回值,那么返回哪个???
class TestMiddle(MiddlewareMixin):def process_request(self,request):print('i am first middleware')return HttpResponse('欢迎来到英雄联盟')
运行结果:
中间件是在执行视图函数之前执行,一般情况下,中间件没有返回值
如果中间件中有返回值了,那么就不在执行视图函数了
3.过滤资源路径
以增删改查为例
创建子路由:
url(r'add/',views.add),
url(r'delete/', views.delete),
url(r'update/', views.update),
url(r'find/', views.find),
生成视图函数:
def add(request):print('连接数据库')return HttpResponse('add')def delete(request):print('连接数据库')return HttpResponse('delete')def update(request):print('连接数据库')return HttpResponse('update')def find(request):print('连接数据库')return HttpResponse('find')
由上可以发现,每次都需连接数据库,耦合度太高,这时就可以使用中间件来减少耦合度
def add(request):return HttpResponse('add')def delete(request):return HttpResponse('delete')def update(request):return HttpResponse('update')def find(request):return HttpResponse('find')
在middleware.py文件中:
class TestMiddle(MiddlewareMixin):# 中间件是在执行视图函数之前执行,一般情况下,中间件没有返回值# 如果中间件中有返回值了,那么就不在执行视图函数了def process_request(self,request):print('中间件连接数据库')
运行结果:
我们可以发现增删改查都可以通过中间件来连接数据库,但是如果我们调用TestMiddle函数,会出现什么情况???
我们会发现在我们不需要连接数据库的时候,中间件也连接了数据库, 这是因为在默认情况下,中间件是作用在所有的视图函数的前面,所以我们需要过滤资源路径
class TestMiddle(MiddlewareMixin):def process_request(self,request):CONN_REQ = ['/final/add/','/final/delete/','/final/update/','/final/find/',]if request.path in CONN_REQ:print('中间件连接数据库')
运行结果:
4.应用-白名单
创建子路由:
url(r'^testWhite/',views.testWhite),
生成视图函数:
def testWhite(request):if random.randrange(100) > 70:return HttpResponse('恭喜你获得三等奖,获得英雄联盟全英雄')else:return HttpResponse('很遗憾,英雄体验卡一张')
运行结果:
设置白名单:
class TestMiddle(MiddlewareMixin):def process_request(self,request):# 白名单IPIP_REQ = ['xxx.xxx.xxx.xxx','xxx.xxx.xxx.xxx']ip = request.META.get('REMOTE_ADDR')print(ip)if ip in IP_REQ:if random.randrange(100) > 50:return HttpResponse('恭喜你中了一等奖,英雄联盟全英雄全皮肤全手办')
运行结果:
5.中间件异常
当某一段业务逻辑发生了错误,那么就会执行process_exception方法,process_exception使得界面友好化,应用交互友好化。
创建子路由:
url(r'^testException/',views.testException),
生成视图函数:
def testException(request):a = 1b = 0print(a / b)return HttpResponse('测试异常')
运行结果:
这个报错界面不是很友好,我们可以进行修改:
在中间件添加:
class TestMiddle(MiddlewareMixin):def process_request(self,request):pass# 判断所有的视图函数,如果视图函数中有异常,然后就要执行process_exceptiondef process_exception(self, request, exception):return HttpResponse('服务器中进入了一个只耗子,稍等片刻。。。')
运行结果:
我们也可以将它跳转到其他页面:
class TestMiddle(MiddlewareMixin):def process_request(self,request):passdef process_exception(self, request, exception):return redirect(reverse('final:index'))
运行结果:
6.中间件的执行顺序
创建新的中间件:
class SecondMiddleware(MiddlewareMixin):def process_request(self,request):print('i am second middleware')
在settings中再次注册一个中间件:
'middleware.middleware.SecondMiddleware',
创建子路由:
url(r'^testMiddleSort/',views.testMiddleSort),
生成视图函数:
def testMiddleSort(request):return HttpResponse('欢迎来到英雄联盟')
运行结果:
思考:执行顺序是书写顺序还是注册顺序???
当我们修改一下注册顺序试试:
'middleware.middleware.SecondMiddleware',
'middleware.middleware.TestMiddle',
运行结果:
由上可知,中间件的执行顺序是按照注册顺序执行的
思考:如果一个中间件进行了返回,其他的中间件是否会执行???
在settings中,中间件的注册顺序:
'middleware.middleware.TestMiddle',
'middleware.middleware.SecondMiddleware',
中间件:
class TestMiddle(MiddlewareMixin):# 中间件是在执行视图函数之前执行,一般情况下,中间件没有返回值# 如果中间件中有返回值了,那么就不在执行视图函数了def process_request(self,request):print('i am first middleware')return HttpResponse('敌军还有5秒抵达战场')class SecondMiddleware(MiddlewareMixin):def process_request(self,request):print('i am second middleware')
运行结果:
由上可知,如果一个中间件进行了返回,其他的中间件不会执行
总结:
中间件的执行顺序
中间件注册的时候是一个列表
如果我们没有在切点处直接进行返回,中间件会依次执行
如果我们直接进行了返回,后续中间件就不再执行了
三.分页器
分页是为了提升用户体验,并且减小服务器的负担而开发的
分页:
真分页:每一次点击下一页或者上一页,都会向数据库发送请求,并且返回数据,访问数据库次数过多
假分页:一次性读取所有数据,然后在内存中进行分页
企业级开发中常用的是真分页
1.原生实现
创建模型:
class Student(models.Model):name = models.CharField(max_length=32)class Meta:db_table = 'student'
添加数据:
创建子路由:
url(r'^testGetPage/',views.testGetPage),
生成视图函数:
def testGetPage(request):#页数page = int(request.GET.get('page',1))#设置每页5条数据per_page = int(request.GET.get('per_page',5))# 规律# 1 0 5# 2 5 10# 3 10 15# 4 15 20#查询student_list = Student.objects.all()[(page-1)*per_page:per_page*page]for student in student_list:print(student.id,student.name)return HttpResponse('分页原生实现')
运行结果:
2.封装实现
使用Django自带的Paginator
Paginator(分页工具)对象创建:Paginator(数据集,每一页数据数)paginator = Paginator(students, per_page)属性count对象总数num_pages:页面总数page_range: 页码列表,从1开始 *方法:page(整数): 获得一个page对象该方法的返回值类型是Page常见错误:InvalidPage:page()传递无效页码PageNotAnInteger:page()传递的不是整数Empty:page()传递的值有效,但是没有数据Page(具体哪一页)对象获得通过Paginator的page()方法获得属性object_list:当前页面上所有的数据对象number:当前页的页码值paginator:当前page关联的Paginator对象方法has_next():判断是否有下一页has_previous():判断是否有上一页has_other_pages():判断是否有上一页或下一页next_page_number():返回下一页的页码previous_page_number():返回上一页的页码len():返回当前页的数据的个数 应用场景:paginator对象:适用于页码的遍历 eg 上一页 xxx 下一页page对象:适用于是否有上一页 、下一页或上一页页码、下一页页码
创建子路由:
url(r'^testDjangoPage/',views.testDjangoPage),
生成视图函数:
Paginator对象:
def testDjangoPage(request):pag = request.GET.get('page',1)per_page = request.GET.get('per_page',5)student_list = Student.objects.all()# Paginator的参数有object_list,per_pagepaginator = Paginator(student_list,per_page)# 适用于上一页和下一页之间的页码for i in paginator.page_range:print(i)# 总页数print(paginator.num_pages)# 一共有多少条(不常用)print(paginator.count)return HttpResponse('django的分页')
运行结果:
page对象:
def testDjangoPage(request):pag = request.GET.get('page',1)per_page = request.GET.get('per_page',5)student_list = Student.objects.all()# Paginator的参数有object_list,per_pagepaginator = Paginator(student_list,per_page)# page方法返回了一个Page对象pa = paginator.page(pag)# 判断是否有上一页print(pa.has_previous())# 判断是否有下一页print(pa.has_next())# 判断是否有上一页页码print(pa.previous_page_number())# 判断是否有下一页页码print(pa.next_page_number())return HttpResponse('django的分页')
运行结果:
四.富文本
富文本:Rich Text Format(RTF),是有微软开发的跨平台文档格式,大多数的文字处理软件都能读取和保存RTF文档,其实就是可以添加样式的文档,和HTML有很多相似的地方,通常在写论坛,博客时使用的一种带样式的文本插件。
安装插件:
pip install django-tinymce==2.8.0
基本使用:
在instatlled_app中添加:tinymce
初始化:
在settings中注册tinymce应用
设置默认的配置文件
TINYMCE_DEFAULT_CONFIG = {'theme':'advanced','width':800,'height':600,}
创建模型:
from tinymce.models import HTMLField
class Blog(models.Model):sBlog = HTMLField()
创建子路由:
url(r'^testRTF/',views.testRTF),
生成视图函数:
def testRTF(request):if request.method == 'GET':return render(request,'testRTF.html')
模板文件:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="/static/tiny_mce/tiny_mce.js"></script><script type="text/javascript">tinyMCE.init({"mode": "textareas","theme": "advanced","width": 800,"height": 600})</script>
</head>
<body>测试富文本<form action="" method="post"><textarea></textarea></form>
</body>
</html>
运行结果:
Django的边边角角(二):缓存、中间件、分页器、富文本相关推荐
- Django (八) 中间件验证码富文本缓存
中间件&验证码&富文本&缓存 1. 中间件&AOP 中间件:是一个轻量级的,底层的插件,可以介入Django的请求和响应过程(面向切面编程) 中间件的本质就是一个p ...
- (转)学习淘淘商城第二十二课(KindEditor富文本编辑器的使用)
http://blog.csdn.net/u012453843/article/details/70184155 上节课我们一起学习了怎样解决KindEditor富文本编辑器上传图片的浏览器兼容性问题 ...
- uniapp 对富文本中的图片预览及长按图片识别二维码/保存图片
uniapp 对富文本中的图片预览及长按图片识别二维码/保存图片 富文本一定要使用uniapp提供的<rich-text>标签,不要使用 v-html 因为<rich-text> ...
- Django中提供了6种缓存方式,你会几种?
开发调试 内存 文件 数据库 Memcache缓存(python-memcached模块) Memcache缓存(pylibmc模块) 1. 开发调试 # 此为开始调试用,实际内部不做任何操作# 配置 ...
- Django中提供了6种缓存方式
开发调试 内存 文件 数据库 Memcache缓存(python-memcached模块) Memcache缓存(pylibmc模块) 1. 开发调试 1 2 3 4 5 6 7 8 9 10 11 ...
- Django中提供的6种缓存方式
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用: 缓存,缓存将一个某个views的返回值保存至内存或者memcache中, ...
- Spring Cache 实战:兼容所有缓存中间件!
作者 | 悟空聊架构 来源 | 悟空聊架构(ID:PassJava666) 本篇给大家介绍一种兼容所有缓存中间件的方案,不论我们是使用 Redis 还是 Ehcache,都不需要关心如何操作 Redi ...
- Django 系列博客(二)
Django 系列博客(二) 前言 今天博客的内容为使用 Django 完成第一个 Django 页面,并进行一些简单页面的搭建和转跳. 命令行搭建 Django 项目 创建纯净虚拟环境 在上一篇博客 ...
- 新课发布-SpringBoot2.0缓存中间件Redis技术入门与实战(抢红包系统设计与实战)
概要介绍:历经半个多月的时间,Debug呕心沥血.亲自录制的 "缓存中间件Redis技术入门与应用场景实战(SpringBoot2.x + 抢红包系统设计与实战)"的新课终于完成了 ...
最新文章
- 值得向IOS学习的15个APP设计技巧!
- 欧拉路径(Euler_Path)和欧拉回路(Euler_Loop)
- 去马赛克神器 JavPlayer TG Modle 最新版
- C语言 字符串大小写转换
- 内推|百度2020春实习-计算机视觉算法研发工程师-北京
- T8 ADS1299开发板的默认设置
- 计算机交叉专业考研方向,与理工科交叉的计算机专业考研方向有哪些?
- 5、优化方法:随机梯度下降法
- 深入理解计算机系统 csapp 家庭作业(第三章完整版)
- three.js 场景编辑器 源码解析(六)
- 一分钟带你快速认识S参数
- unity 刚体的运动 减速运动
- 教你用Python绘制炫酷专业插图
- Cay S.Horstmann:从Java新特性看Java的未来
- 开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)
- 最简单的删除重复记录(只保留一条)的SQL方法
- 锁模块之当前读和快照读
- MySql基础:3.DML语言介绍
- 第59期、基于Java springboot医院信息管理系统
- Win11的两个实用技巧系列之u盘怎么设置密码?
热门文章
- 计算机自带游戏如何删除,详细教你系统怎么删除游戏
- [附源码]Java计算机毕业设计SSM宠物寄养预约系统
- 我们公司楼下新开了菜鸟驿站
- 复合线上加点_这4个英雄主加点千万别搞错,否则线上崩了你都不知道为什么...
- Linux: sysctl 及 sysctl 配置选项说明
- gmod无法连接更新服务器未响应,steam gmod更新不动 | 手游网游页游攻略大全
- 转:人生成功必读的经典语录200条
- Swin Transformer: Hierarchical Vision Transformer using Shifted Windows论文阅读
- Java TCP 抓包简单示例
- 简单三步,教你如何用小度音箱语音控制智汀设备?