三、缓存
缓存是可以在任何地方,如内存、文件、数据库、其他机器的内存等。
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 %}
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Titletitle>
- head>
- <body>
- <h1>{{ v }}h1>
- {% cache 20 key-11 %}
- <h3>{{ v }}h3>
- {% endcache %}
- body>
- html>
这里会缓存
访问时:在缓存时间内,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
测试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
xxoo_callback2
对于callback,是pre_init信息注册的,在实例化前执行,sender是
对于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':
应用场景:预留插拔接口,如某操作后,需要发送提醒,一开始是短信,后来增加邮件,在增加微信、QQ等,这时使用信号,只要增加callback函数,注册信号就行。
五、BootStrap,集成了css、js一个文件夹 --- 响应式+模板
css:在前端网页中引入相应的css,在head中:
响应式:
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Titletitle>
- <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