文章目录

  • 一.缓存
    • 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的边边角角(二):缓存、中间件、分页器、富文本相关推荐

  1. Django (八) 中间件验证码富文本缓存

    中间件&验证码&富文本&缓存 1. 中间件&AOP 中间件:是一个轻量级的,底层的插件,可以介入Django的请求和响应过程(面向切面编程) ​ 中间件的本质就是一个p ...

  2. (转)学习淘淘商城第二十二课(KindEditor富文本编辑器的使用)

    http://blog.csdn.net/u012453843/article/details/70184155 上节课我们一起学习了怎样解决KindEditor富文本编辑器上传图片的浏览器兼容性问题 ...

  3. uniapp 对富文本中的图片预览及长按图片识别二维码/保存图片

    uniapp 对富文本中的图片预览及长按图片识别二维码/保存图片 富文本一定要使用uniapp提供的<rich-text>标签,不要使用 v-html 因为<rich-text> ...

  4. Django中提供了6种缓存方式,你会几种?

    开发调试 内存 文件 数据库 Memcache缓存(python-memcached模块) Memcache缓存(pylibmc模块) 1. 开发调试 # 此为开始调试用,实际内部不做任何操作# 配置 ...

  5. Django中提供了6种缓存方式

    开发调试 内存 文件 数据库 Memcache缓存(python-memcached模块) Memcache缓存(pylibmc模块) 1. 开发调试 1 2 3 4 5 6 7 8 9 10 11 ...

  6. Django中提供的6种缓存方式

    由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用: 缓存,缓存将一个某个views的返回值保存至内存或者memcache中, ...

  7. Spring Cache 实战:兼容所有缓存中间件!

    作者 | 悟空聊架构 来源 | 悟空聊架构(ID:PassJava666) 本篇给大家介绍一种兼容所有缓存中间件的方案,不论我们是使用 Redis 还是 Ehcache,都不需要关心如何操作 Redi ...

  8. Django 系列博客(二)

    Django 系列博客(二) 前言 今天博客的内容为使用 Django 完成第一个 Django 页面,并进行一些简单页面的搭建和转跳. 命令行搭建 Django 项目 创建纯净虚拟环境 在上一篇博客 ...

  9. 新课发布-SpringBoot2.0缓存中间件Redis技术入门与实战(抢红包系统设计与实战)

    概要介绍:历经半个多月的时间,Debug呕心沥血.亲自录制的 "缓存中间件Redis技术入门与应用场景实战(SpringBoot2.x + 抢红包系统设计与实战)"的新课终于完成了 ...

最新文章

  1. 值得向IOS学习的15个APP设计技巧!
  2. 欧拉路径(Euler_Path)和欧拉回路(Euler_Loop)
  3. 去马赛克神器 JavPlayer TG Modle 最新版
  4. C语言 字符串大小写转换
  5. 内推|百度2020春实习-计算机视觉算法研发工程师-北京
  6. T8 ADS1299开发板的默认设置
  7. 计算机交叉专业考研方向,与理工科交叉的计算机专业考研方向有哪些?
  8. 5、优化方法:随机梯度下降法
  9. 深入理解计算机系统 csapp 家庭作业(第三章完整版)
  10. three.js 场景编辑器 源码解析(六)
  11. 一分钟带你快速认识S参数
  12. unity 刚体的运动 减速运动
  13. 教你用Python绘制炫酷专业插图
  14. Cay S.Horstmann:从Java新特性看Java的未来
  15. 开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)
  16. 最简单的删除重复记录(只保留一条)的SQL方法
  17. 锁模块之当前读和快照读
  18. MySql基础:3.DML语言介绍
  19. 第59期、基于Java springboot医院信息管理系统
  20. Win11的两个实用技巧系列之u盘怎么设置密码?

热门文章

  1. 计算机自带游戏如何删除,详细教你系统怎么删除游戏
  2. [附源码]Java计算机毕业设计SSM宠物寄养预约系统
  3. 我们公司楼下新开了菜鸟驿站
  4. 复合线上加点_这4个英雄主加点千万别搞错,否则线上崩了你都不知道为什么...
  5. Linux: sysctl 及 sysctl 配置选项说明
  6. gmod无法连接更新服务器未响应,steam gmod更新不动 | 手游网游页游攻略大全
  7. 转:人生成功必读的经典语录200条
  8. Swin Transformer: Hierarchical Vision Transformer using Shifted Windows论文阅读
  9. Java TCP 抓包简单示例
  10. 简单三步,教你如何用小度音箱语音控制智汀设备?