Django框架学习--8--缓存&中间件

本篇要点:

        1.如何通过缓存做出更快的做出响应?

        2.什么是中间件?

        3.网站的分页功能如何实现?

        4.生成csv文件

1. 缓存

什么是缓存?

  1.  一类可以更快的读取数据的介质或加快数据读取的存储方式;
  2.  一般用于存储临时数据;
  3.  常用介质的是读取速度很快的内存。

网站的响应速度限制门槛:

        网速不是主要门槛,主要在后端的数据库中,由于数据表过多,或sql查询的方式不当,导致后台数据传入前端显示过慢。

Django提供的缓存优化方案:

given a URL, try finding that page in the cache

if the page is in the cache: 
    return the cached page
else: 
    generate the page ,
    save the generate page in the cacher(for next time) 
    return the generated page;

缓存场景:

  • 博客列表,电商商品详情页
  • 场景特点:缓存的地方,数据变动频率较少

django中配置缓存

1.数据库缓存

        缓存介质是后端数据库,尽管缓存介质没有更换,但当把一次负责查询的结果直接存储到表中,避免重复进行复杂查询。

settings.py文件中的CACHES字段相关配置

# 数据库缓存配置-数据库缓存 (需要手动创建cache表)
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
        'TIMEOUT': 300, #缓存保存时间 单位秒, 默认值为300,
        'OPTIONS': {
            'MAX_ENTRIES': 300, #缓存最大数据条数
            'CULL_FREQUENCY': 2, #缓存条数达到最大值时,删除1/x的缓存数据
        }
    }
    
}

2.浏览器缓存

浏览器缓存的工作流程图:

Django框架学习--8--缓存&中间件

浏览器缓存分为两种类型:强缓存、协商缓存

强缓存

不会向服务器发送请求,直接从缓存中读取资源

  • 响应头-expires :指定资源的过期时间
  • 响应头-Cache-Control : 请求创建时间后的多少秒,缓存失效(优先判断该字段)

协商缓存

强缓存中的数据一旦过期,还需要跟服务器进行通信,从而获取最新数据(对于一些大文件)

 协商缓存-方式一

  • 响应头-Last-Modified :文件的最近修改时间
  • 请求头-if-Modified-Since : 对服务器发送协商,服务端返回304响应【代表缓存继续使用】,200响应代表缓存不可用【响应体为最新资源】

协商缓存-方式二

  • ETag响应头 -返回当前资源文件的一个唯一标识(哈希值)
  • If-None-Match请求头 - 协商结果与上面策略一致

3.其他类型缓存

  1. 数据缓存到服务器内存中(测试型,一般都存放在redis中)
  2. 文件系统缓存(不推荐)

怎么使用缓存?

1.整体缓存策略

  • 视图函数中

        使用方法:在视图函数前添加装饰器@cache_page(参数);后面参数表示当前视图函数的缓存存活多久;

        作用:缓存中有请求的数据则直接返回,没有则走视图函数并把结果返回给装饰器以便下次存储。

示例代码中前面的缓存数据存活15秒 ,从获取时间戳到15秒之前都不会改变,直到到15秒后才会改变。

@cache_page(15)
def test_cache(request):
    t = time.time()
    return HttpResponse('t is %s' %(t))
  • 路由中
from jdango.views.decorators.cache import cache_page

urlpatterns = [
    path('foo/', cache_page(15)(my_view)),
]

2.局部缓存策略

缓存API(应用程序编程接口)的使用,调用方式和字典类似

# 方式1
from django.core.cache import caches
cache1 = caches['myalias']

# 方式2
from django.core.cache import cache
# 相对于直接引入CACHES配置项中的'default'项

cache的存储 、获取、删除方法:

# 存储缓存
cache.set(key, value, timeout) 
cache.add(key, value) # 只有在key不存在时生效
cache.set_many(dict, timeout) # 返回插入不成功的key的数组
# 获取缓存
cache.get(key)
cache.get_many(key_list)
cache.get_or_set(key,value,timeout)
#删除缓存
cache.delete(key)
cache.delete_many(key_list)


2. 中间件

什么是中间件?

  1. django请求、响应的钩子框架,一个轻量级的、低级的‘插件’系统,用于全局改变Django的输入或输出;
  2. 过滤响应,过滤路由,过滤视图等,相当与收费站;比如在请求到达主路由之前在前面置于中间件;
  3. 中间件以类的形式体现,每个中间件组件负责做一些特定的功能。

中间件的原理图

Django框架学习--8--缓存&中间件

如何编写中间件

1.编写中间件

创建与manage.py同级目录的middleware文件夹,再在里面创建__init__.py和mymiddleware.py(自定义文件名)模块,之后的中间件都在自定义文件名模块中书写;

中间件书写要求:

  1. 中间件必须继承django.utils.deprecation.MiddlewareMixin类;
  2. 中间件须实现下列五种方法中的一个或多个。
process_request(self, request)
#执行路由之前会被调用,在每一个请求上调用,返回None或HttpResponse对象(被阻止)
process_view(self, request, callback, callback_args, callback_kwargs)
#调用视图之前被调用,在每个请求上调用,返回None或HttpResponse对象
#callback视图函数,callback_args位置传参,callback_kwargs关键字传参
process_response(self, request, response)
# 所有响应返回浏览器被调用,在每个请求上调用,返回HttpResponse对象
process_exception(self, request, exception)
# 当处理过程中抛出异常时调用, 返回一个HttpResponse对象
process_template_reponse(self, request, response)
# 在视图函数执行完毕且视图返回对象中包含render方法时被调用,该方法需要返回实现render方法的响应对象

上述大多数方法返回None时表示忽略当前操作进行下一项事件

返回HttpResponse对象时表示此请求结束,直接返回给客户端

2.注册中间件

#settings.py
MIDDLEWARE=[
    'middleware.mymiddleware.MyMW',
]

django调用中间件类是以注册中间件顺序从上到下处理请求,再从下到上返回响应。

案例

使用中间件实现强制某个IP地址只能向/test开头的地址,发送5次请求


class VisitLimit(MiddlewareMixin):
    
    visit_times = {}
    
    def process_request(self, request):
        # 访问者的地址和路由
        ip_address = request.META['REMOTE_ADDR'] 
        path_url = request.path_info 
        # 使用正则匹配
        if not re.match('^/test', path_url):
            return 
        times = self.visit_times.get(ip_address, 0)
        print('ip', ip_address, '已经访问', times)
        self.visit_times[ip_address] = times + 1
        if times < 5:
            return
        return HttpResponse('您已经访问过' + str(times)+ '次, 禁止访问')

注意:如果想要访问次数撤销、重新计时的话,可以重启本地服务器,把相当与内存值(变量)的visit_times的重置


3. CSRF攻击-跨站伪造请求攻击

利用了Cookies中保存了登录状态且自动提交

解决方案:

  1. 打开settings中MIDDLEWARE中Csrf是否打开
  2. 模版中,form标签中添加标签{% csrf_token %}

如果某个视图不需要django进行csrf保护,可以用装饰器关闭对此视图的检查

@csrf_exempt
def my_view(request):
        return HttpResponse('hi')

4. 分页功能

分页功能的作用

  1. 方便阅读
  2. 减少数据提取量,减轻服务器压力

Django如何实现分页功能?

        Paginator类可以方便的实现分页功能(负责分页数据整体的管理)

Paginator对象

对象的构造方法

paginator = Paginator(object_list, per_page)

参数的含义:

  • object_list需要分类数据的对象列表
  • per_page每页数据个数

Paginator属性

  • count  分页数据的对象总数
  • num_pages 分页后的页面总数
  • page_range  从一开始的range对象
  • per_page 返回第二个参数

 Page对象

        由于Paginator对象只能处理分页数据整体,不能对某一页进行管理,这里我们引用page对象,他可以负责具体某一页的数据的管理

对象的构造方法

page1 = paginator对象.page(页码)

生成page对象-管理某一页的数据的管理

Page对象属性

  • object_list 当前页上所有的数据对象的列表
  • number 当前页的序号,从1开始
  • paginator 当前page对象相关的Paginator对象

案例

编写视图函数

def test_page(request):
    # test_page/4
    # test_page?page=1
    page_num = request.GET.get('page', 1)
    all_data = ['a', 'b', 'c', 'd', 'e']
    paginator = Paginator(all_data, 2)
    c_page = paginator.page(int(page_num))
    return render(request, 'test_page.html', locals())

模版中html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>分页</title>
</head>
<body>
    {% for p in c_page %}
    <p>
        {{ p }}
    </p>
    {% endfor %}

    {% if c_page.has_previous %}
    <a href="/test_page?page={{ c_page.previous_page_number }}">往上走</a>
    {% else %}
        往上走
    {% endif %}
    {% for p_num in paginator.page_range %}
        {% if p_num == c_page.number %}
        {{ p_num }}
        {% else %}
        <a href="/test_page?page={{ p_num }}">{{ p_num }}</a>
        {% endif %}
    {% endfor %}
    {% if c_page.has_next %}
    <a href="/test_page?page={{ c_page.next_page_number }}"> 往下去 </a>
    {% else %}
        往下去
    {% endif %}
    
</body>
</html>

实现效果:

Django框架学习--8--缓存&中间件


5. 生成csv文件

  • 逗号分隔值(字符分隔符)
  • 可被常见制表工具,如excel等直接进行读取

csv编写

import csv

with open('csv.csv', 'w', newline='') as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(['a','b','c'])
#简单描述一下,具体内容可上其他教学内容查询 

csv文件下载

  1. 响应Content-Type类型修改为text/csv
  2. 响应会获得一个额外的Content-Disposition标头,它将被浏览器用于开启"另存为"对话框

案例

只需在上一个案例的html文件中的body标签内加入以下代码:

<a href="/make_page_csv?page={{ c_page.number }}">生成csv文件</a>

实现效果:

Django框架学习--8--缓存&中间件

上一篇:SpringCloud学习后获取的地址


下一篇:Flex TextInput的restrict属性应用