三、缓存
?
缓存是可以在任何地方,如内存、文件、数据库、其他机器的内存等。
Django提供的缓存机制:
1、开发调试(虚拟缓存) 2、内存? (本地内存) 3、文件 4、数据库 5、Memcache缓存(python-memcached模块)? ? (分布式内存) 6、Memcache缓存(pylibmc模块)? ? ? ? ? ? ? ? ? ?(分布式内存)
设置缓存:
缓存系统需要少量的设置。必须知道缓存数据应该放在哪里 —— 是在数据库中,还是在文件系统上,或者直接放在内存中。这是一个重要的决定,会影响你的缓存的性能;有些缓存类型比其他类型快。
缓存设置项位于配置文件的缓存配置中。
在settings.py中增加:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎
'TIMEOUT': 300, # 缓存超时时间,默认300,None表示永不过期,0表示立即过期
'OPTIONS': {
'MAX_ENTRIES': 300, # 最大缓存条数,默认300
'CULL_FREQUENCY': 3, # 当达到 MAX_ENTRIES 时,被删除的条目的比例。实际比例是 1 / CULL_FREQUENCY
},
'KEY_PREFIX': '', # 缓存key的前缀(默认空
'VERSION': 1, # 缓存key的版本,默认1
'KEY_FUNCTION': hanshu_函数名, # 生成key的函数,默认函数会生成:【前缀:版本:key】
}
}
上面是开发调试,即虚拟缓存的配置,其他的缓存,主要是BACKEND的不同:
'django.core.cache.backends.db.DatabaseCache' 'django.core.cache.backends.dummy.DummyCache' 'django.core.cache.backends.filebased.FileBasedCache' 'django.core.cache.backends.locmem.LocMemCache' 'django.core.cache.backends.memcached.PyMemcacheCache' 'django.core.cache.backends.memcached.PyLibMCCache'
另外还有一个重要的配置项是LOCATION,指定缓存的位置。
对于内存缓存,'django.core.cache.backends.locmem.LocMemCache',其LOCATION指定缓存的名字,相当于一个变量名,内存缓存就是内存中的一块区域,可以看成是一个字典,这里的LOCATION就是这个字典的名字,‘LOCATION’:‘unique-snowflake’,
对于文件缓存,'django.core.cache.backends.filebased.FileBasedCache',其LOCATION指定缓存的文件夹位置,如'LOCATION': '/var/tmp/django_cache',
对于数据库缓存,'django.core.cache.backends.db.DatabaseCache',其LOCATION指定缓存的数据库表名,如‘LOCATION’:‘my_cache_table’,需要执行创建表命令:python manage.py createcachetable
对于Memcache——python-memcached,'django.core.cache.backends.memcached.PyMemcacheCache',其LOCATION指定另外一台机器:
1)‘LOCATION’:‘127.0.0.1:11211’,? 以IP和端口方式连接
2)‘LOCATION’:‘unix:/tmp/memcached.sock’,以socket方式连接,一个文件,文件中写了连接信息,只能连本机。
3)'LOCATION':['172.1.1.1:12211','172.1.1.2:12211',],一个列表指定多台机器,就是集群了,还可以列表中是元组项,指定权重: 'LOCATION':[('172.1.1.1:12211',10),('172.1.1.2:12211',20),],
对于'django.core.cache.backends.memcached.PyLibMCCache'同上面。
应用:主要有全站使用、单独视图缓存、局部视图使用
1、单独视图缓存
首先配置settings,然后使用装饰器cache_page:
# settings中的配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': os.path.join(BASE_DIR,'cache'),
}
}
单独的视图函数使用装饰器来使用缓存:
# 后台视图函数,引入装饰器,对单独函数使用缓存
from django.views.decorators.cache import cache_page
@cache_page(20) # 参数代表超时时间,单位是秒
def cache(req):
import time
v = time.time()
print(v)
return HttpResponse(v)
运行后,在文件夹中出现内容了:
?看运行结果:
?第一次请求时,视图函数运行打印了时间,后来的请求都没有运行,20秒后,缓存过期,函数又运行了,打印。
2、局部缓存使用,(前端页面的部分缓存)
使用在模板上,在模板中,先引入模板标签,即引入TemplateTag:{% load cache %}
然后使用缓存:{% cache 10 缓存key %} 缓存内容 {% endcache %}
视图函数:
def part(req):
import time
v = time.time()
print(v)
return render(req,'part.html',{'v':v})
前端模板:
{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ v }}</h1>
{% cache 20 key-11 %}
<h3>{{ v }}</h3>
{% endcache %}
</body>
</html>
这里会缓存<h3>的内容,在缓存中,其键的值会是“:1:key-11”。
访问时:在缓存时间内,H1数据一直变化,H3是不变的,这个数据从缓存中来。
?后台的打印结果:
每次请求都打印,即都执行了函数,说明函数没有缓存。?
3、全站使用,(要使用中间件)
一般使用两个中间件,一个放在中间件链的开始,一个放在最后,放在最后的中间件,执行process_request,放在第一个的中间件,执行process_response。
这样放的理由:一个请求的到来,是需要经过所有process_request的,相当于过安检,安检过后,才能判断是否在缓存中,也就是在执行视图函数前判断缓存,如果不放在最后一个,有可能安检不通过也能获取数据了,这是放在最后中间件的原因,这个中间件是取缓存的功能,还要有一个中间件放在第一位置,主要执行数据的缓存功能,是执行process_response,这是因为对于返回的内容,其他中间件有可能会进行修改,如果不是第一个,就不是最后执行process_response的中间件,所缓存的内容可能不是最终的内容。(一定要与前面中间件的执行顺序相结合进行理解)。
这两个中间件一个是'django.middleware.cache.UpdateCacheMiddleware'——更新缓存内容,实现内容的缓存和'django.middleware.cache.FetchFromCacheMiddleware'——从缓存中获取内容。
配置如下:
MIDDLEWARE = [ ????????'django.middleware.cache.UpdateCacheMiddleware', ? ? ? ? # 其他中间件。。。 ????????'django.middleware.cache.FetchFromCacheMiddleware', ]
这样配置后,全站缓存就启用了。
这时再访问前面的part页面时,H1和H3的内容都不变了,都进行了缓存。
?四、信号(Django预留的钩子)
Django有一个“信号调度器(signal dispatcher)”,用来帮助解耦的应用获知框架内任何其他地方发生了操作。简单地说,信号允许某些?发送器?去通知一组?接收器?某些操作发生了。当许多代码段都可能对同一事件感兴趣时,信号特别有用。
内置信号集 使用户代码能够获得 Django 自身某些操作的通知
内置信号:
Model signals ? ? 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 ? ? ? ? ?# 创建数据库连接时,自动触发
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:
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): ? ? print("xxoo_callback") ? ? print(sender,kwargs)
xxoo.connect(callback) # xxoo指上述导入的内容,即pre_init、post_init等,如pre_init.connect(callback)
注册的时机,因为是要对所有的一类操作进行信号处理,所有要程序一运行就要注册上去。所以一般写在应用的__init__.py中。
启动项目,会打印:
xxoo_callback <class 'django.db.backends.sqlite3.base.DatabaseWrapper'> {'signal': <django.dispatch.dispatcher.Signal object at 0x000000000B796160>, 'connection': <django.db.backends.sqlite3.base.DatabaseWrapper object at 0x000000000AD99C50>}?
测试model的信号pre_init和post_init:
创建models类:
from django.db import models
# Create your models here.
from django.db import models
class User(models.Model):
username = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
注册信号:
from django.db.backends.signals import connection_created
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
def callback(sender,**kwargs):
print("xxoo_callback")
print(sender,"-----",kwargs)
def callback2(sender,**kwargs):
print("xxoo_callback2")
print(sender,"-----",kwargs)
connection_created.connect(callback)
pre_init.connect(callback)
post_init.connect(callback2)
视图函数:
def signal(req):
from midwares import models
oo = models.User(username='root',pwd='123')
return HttpResponse('ok')
urls中增加 : path('signal/',views.signal),
前端访问signal:打印结果
xxoo_callback <class 'midwares.models.User'> ----- {'signal': <django.db.models.signals.ModelSignal object at 0x000000000AFF3198>, 'args': (), 'kwargs': {'username': 'root', 'pwd': '123'}} xxoo_callback2 <class 'midwares.models.User'> ----- {'signal': <django.db.models.signals.ModelSignal object at 0x000000000AFF34A8>, 'instance': <User: User object (None)>}
对于callback,是pre_init信息注册的,在实例化前执行,sender是<class 'midwares.models.User'>,说明是User类触发的信号,参数中args是位置参数,这里没有传递位置参数,kwargs是我们创建User类对象时传递的参数,username=root,pwd=123,这些就可以在实例化前进行记录。
对于callback2,是实例化后执行的,参数instance是实例化后的对象
以上是Django定义的内置信号,下面我们自定义自己的信号:
1)定义信号: import django.dispatch pizza_done = django.dispatch.Singnal(providing_args=["toppings","size"])
def mysignal(req):
from midwares import pizza_done # 从应用的__init__.py模块中引入,只需写应用的名,不必加__init__
pizza_done.send(sender='调用者',toppings='123',size='456') # 自定义的信号,需要自己主动触发,触发就是调用send方法
return HttpResponse('ok')
2)注册信号: 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)
示例测试:
在__init__.py中定义信号和注册信号:
# 以下是定义信号
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=['toppings','size'])
# 定义回调函数,注册信号
def callback3(sender,**kwargs):
print("自定义信号callback3")
print(sender,kwargs)
pizza_done.connect(callback3)
触发信号:在视图函数中需要自己触发
def mysignal(req):
from midwares import pizza_done # 从应用的__init__.py模块中引入,只需写应用的名,不必加__init__
pizza_done.send(sender='调用者',toppings='123',size='456') # 自定义的信号,需要自己主动触发,触发就是调用send方法
return HttpResponse('ok')
运行结果:
自定义信号callback3 调用者 {'signal': <django.dispatch.dispatcher.Signal object at 0x000000000B786198>, 'toppings': '123', 'size': '456'}
应用场景:预留插拔接口,如某操作后,需要发送提醒,一开始是短信,后来增加邮件,在增加微信、QQ等,这时使用信号,只要增加callback函数,注册信号就行。
五、BootStrap,集成了css、js一个文件夹? ---? ?响应式+模板
css:在前端网页中引入相应的css,在head中:<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css" >
响应式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap-5.1.3-dist/css/bootstrap.css">
<style>
.pg-header{
height: 48px;
background-color: black;
}
@media (max-width: 700px) {
.extra{
background-color: yellow;
}
}
</style>
</head>
<body>
<div class="pg-header extra"></div>
</body>
</html>
?
?上面的页面,随着浏览器窗口宽度的变化,在700px以上,div的背景是黑色,缩小的700px以下时,背景变为黄色。这就是响应式。主要是使用@media,bootstrap中的container就是响应式容器
bootstrap中提供了栅格的样式:col-sm-xx,col-md-xx
js:需要先引入jQuery,然后引入bootstrap.js
|