三、緩存
緩存是可以在任何地方,如內存、文件、數據庫、其他機器的內存等。
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