• Django框架13 /缓存、信号、django的读写分离


    Django框架13 /缓存、信号、django的读写分离

    1. 缓存

    • 缓存简述:

      缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行views中的操作,而是直接从内存或者memcache中之前缓存的内容拿到,并返回。
      
    • Django中缓存的方式

      开发调试
      内存
      文件
      数据库
      Memcache缓存(python-memcached模块)
      Memcache缓存(pylibmc模块)
      
    • 各种方式的配置

      1、将缓存内容保存在内存的变量中(django的默认配置)

      # settings配置文件中写如下配置:
      
      CACHES = {
      	'default': {
      		'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
      		'LOCATION': 'unique-snowflake',  #这是一个唯一标示,写啥都行
      		'TIMEOUT': 300,  # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
      		'OPTIONS':{
      			'MAX_ENTRIES': 300,  # 最大缓存个数(默认300)
      			'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
      		},
      } } 
      

      2、将缓存内容保存在文件中

      # settings配置文件中写如下配置:
      
      CACHES = {
      	'default': {
      		'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
      		'LOCATION': '/var/tmp/django_cache', #缓存文件存放路径
      	}
      }
      

      3、将缓存内容保存在数据库中

      # settings配置文件中写如下配置:
      
      # 方式一:执行创建表命令生成数据库表
      CACHES = {
      	'default': {
      		'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
      		'LOCATION': 'my_cache_table', # 数据库表
      	}
      }
      
      # 注:执行创建表命令 python manage.py createcachetable,数据库中会自动生成名字为my_cache_table的表作为缓存表
      
      # 方式二:自己创建存放缓存内容的数据库表
      from django.db import models
      
      class CacheTalbe(models.Model):
          cache_key = models.CharField(max_length=2000)
          value = models.CharField(max_length=2000,null=True)
          expires = models.DateTimeField(null=True)
          
      # 注:如果自己手动创建这个缓存表的时候,数据库表的三个字段是必须要有的:看下面的表,并且不需要制定上面的createcachetable指令就可以使用。
      

      4、将缓存内容保存在redis中

      # settings配置文件中写如下配置:
      
      CACHES = {
          "default": {
              "BACKEND": "django_redis.cache.RedisCache",
              "LOCATION": "redis://127.0.0.1:6379",
              "OPTIONS": {
                  "CLIENT_CLASS": "django_redis.client.DefaultClient",
              }
          }
      }
      
    • 缓存的使用

      1、单独视图使用缓存

      # 方式一:语法糖装饰器
      from django.views.decorators.cache import cache_page
      import time
      @cache_page(5)  # 设置5秒后缓存到期
      def my_view(request):
      	tm = time.time()  # 用时间戳模拟测试
        return render(request,'index.html',{'tm':tm })  # 刷新页面,5s内会一直使用缓存
      
      # 方式二:装饰器原始用法
      from django.views.decorators.cache import cache_page
      urlpatterns = [
      	url(r'^foo/([0-9]{1,2})/$', cache_page(5)(my_view)),
      ]
      

      2、模板局部使用缓存,就不需要在视图中设置缓存了

      <!-- 用法如下: -->
      
      a. 引入TemplateTag
      {% load cache %}
      
      b. 使用缓存
      {% cache 5 key %}  <!-- key就是存储缓存时的键 -->
      	缓存的内容
      {% endcache %}
      
      <!-- 示例代码如下: -->
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
      
      <h1>测试模板局部使用缓存</h1>
      <h2>{{ tm }}</h2>
      
      {% load cache %}
      {% cache 5 'key' %}
      <h2>{{ tm }}</h2>
      {% endcache %}
      
      </body>
      </html>
      

      3、全局使用缓存

      # settings配置文件进行如下配置:
      
      MIDDLEWARE = [
      	'django.middleware.cache.UpdateCacheMiddleware', # 中间件第一个
      	# 其他中间件...
      	'django.middleware.cache.FetchFromCacheMiddleware', # 中间件最后一个
      ]
      
      CACHE_MIDDLEWARE_ALIAS = ""    # 用于存储的缓存别名。
      CACHE_MIDDLEWARE_SECONDS = ""  # 缓存的过期秒数
      CACHE_MIDDLEWARE_KEY_PREFIX = ""  # 如果使用同一django安装跨多个站点共享缓存,请将其设置为站点名称或此django实例唯一的其他字符串,以防止密钥冲突。如果不在乎,就用空字符串。 
          
      # 注意:使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存
      
    • 总结:

      • 缓存是以加密的形式进行保存的
      • 对实时性数据要求很高的,不要做缓存

    2. 信号

    • 信号简述:

      Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
      
    • Django内置的信号

      pre_init                    # django的model执行其构造方法前,自动触发
      post_init                   # django的model执行其构造方法后,自动触发
      pre_save                    # django的model对象保存前,自动触发,新增或者更新都是保存
      post_save                   # django的model对象保存后,自动触发
      pre_delete                  # django的model对象删除前,自动触发
      post_delete                 # django的model对象删除后,自动触发
      m2m_changed                 # django的model中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
      class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
      Management signals
      pre_migrate                 # 执行migrate命令前,自动触发
      post_migrate                # 执行migrate命令后,自动触发
      Request/response signals
      request_started             # 请求到来前,自动触发
      request_finished            # 请求结束后,自动触发
      got_request_exception       # 请求异常后,自动触发
      Test signals
      setting_changed             # 使用test测试修改配置文件时,自动触发
      template_rendered           # 使用test测试渲染模板时,自动触发
      Database Wrappers
      connection_created          # 创建数据库连接时,自动触发
      
    • 信号的使用

      1、注册指定信号,当程序执行相应操作时,自动触发注册函数

      from django.core.signals import request_finished
      from django.core.signals import request_started
      from django.core.signals import got_request_exception
      
      from django.db.models.signals import class_prepared
      from django.db.models.signals import pre_init, post_init
      from django.db.models.signals import pre_save, post_save
      from django.db.models.signals import pre_delete, post_delete
      from django.db.models.signals import m2m_changed
      from django.db.models.signals import pre_migrate, post_migrate
      
      from django.test.signals import setting_changed
      from django.test.signals import template_rendered
      
      from django.db.backends.signals import connection_created
      
      
      def callback(sender, **kwargs):  # sender表示信号触发者
      	print("已经触发信号了")
      	print(sender,kwargs)
      
      post_save.connect(callback)  # 表示model对象保存后,会自动触发callback函数
      
      # 在视图中或者项目或者应用的__init__.py文件中注册信号
      

      2、在视图函数中,做相应的操作就会触发相应的函数

      from app01 import models
      
      def func(sender,**kwargs):
      	models.Book.objects.create(title='python')
      	return HttpReponse('ok')
      
    • 自定义信号

      1、定义信号:在某py文件或者项目或者应用的__init__.py文件中定义信号。

      import django.dispatch
      pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
      
      # 注意:toppings和size这两个参数名称随便,不是固定的,但是使用的时候关键字传参的时候,要和这两个参数的名称对应好,可以通过设置参数来进行一个判断处理等操作
      

      2、注册信号:在__init__.py中注册信号

      def callback(sender, **kwargs):
          print("callback")
          print(sender,kwargs)
       
      pizza_done.connect(callback)
      

      3、触发信号

      from 路径 import pizza_done
       
      pizza_done.send(sender='seven',toppings=123, size=456) 
      

    3. django的读写分离

    • django的读写分离简述:

      django做的其实是在数据库已经做好读写分离的情况下,怎么使用
      
    • 首先配置多个数据库,在settings配置文件中配置以下内容:

      DATABASES = {
          'default': { # 默认数据库,配置多个mysql数据也是ok的,混用数据库也是ok的
              'ENGINE': 'django.db.backends.sqlite3',
              'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
          },
          'db2': { # 配置的第二个数据库,注意数据库名字不能相同
              'ENGINE': 'django.db.backends.sqlite3',
              'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
          }
      }
      
    • 执行数据库同步指令,将默认数据库的表结构生成到db2这个数据库中

      python migrate --database db2(库名)
      
    • django使用读写分离

      1、手动实现,在views.py文件中进行操作时指定数据库

      def dbtest(request):
          data = []
          # 向db2数据库中写入数据
          models.Class.objects.using('db2').create(name='xx')
      
          # 从默认数据库中读取数据
          data = models.Class.objects.using('default').all()
          # 更新时
          for i in data:
              i.name = '张三'
              i.save(using='default')  # 更新时指定数据库
          return render(request,'dbtest.html',{'data':data})
      

      2、自动实现,进行相关配置

      # 在应用文件夹中创建一个py文件,比如叫做router.py文件,写如下内容:
      
      class Router:
          def db_for_read(self,model,**kwargs):
              return 'default'
      
          def db_for_write(self,model,**kwargs):
              return 'db2'
      
      # settings配置文件做如下配置
      
      DATABASE_ROUTERS = ['app01.router.Router',] 
      # []中写上面Router类的路径
      
      # 在views.py中,进行读写操作时,会自动操作不同的数据库
      
      def dbtest(request):
          data = []
          # 向db2数据库中写入数据
          models.Class.objects.create(name='李四')
      
          # 从默认数据库中读取数据
          data = models.Class.objects.all()
      
          return render(request,'dbtest.html',{'data':data})
      
    • 一主多从的时候,也就是从多个数据库中读取的时候:

      1、多个数据库进行随机读取的

      import random
      class Router:
          def db_for_read(self,model,**kwargs):
              print(model._meta.app_label)
              return random.choice(['db1','db2','db3'])  # 多个库读的时候,可以简单的写个随机选择
      
          def db_for_write(self,model,**kwargs):
              return 'db2'
      

      2、根据不同的应用来选择不同的库进行读取

      class Router:
          def db_for_read(self,model,**kwargs):
              print(model)
              print(dir(model))  # 其中有个_meta属性很有用
              app_name = model._meta.app_label  # 获取当前model对象所在的应用名称
           m = model._meta.model_name  # 获取当前操作的model对象的表名,也可以根据表名来进行多数据库读的分配
      
              # 可以根据应用选择不用的库来进行读取
              if app_name == 'app01':
                  return 'db1'
              elif app_name == 'app02':
                  return 'db2'
              return 'default'
      
          def db_for_write(self,model,**kwargs):
      
  • 相关阅读:
    Spring学习笔记
    Bash编程(6) String操作
    Bash编程(5) Shell方法
    Bash编程(4) 参数与变量
    Bash编程(2) 循环与分支
    CentOS 升级 openSSH
    Bash编程(1) 基础
    DNS配置
    资料收集:学习 Linux/*BSD/Unix 的 30 个最佳在线文档
    【数位DP】[LOJ10168] 恨7不成妻
  • 原文地址:https://www.cnblogs.com/liubing8/p/12150648.html
Copyright © 2020-2023  润新知