django—中間件|CSRF|緩存|信號|BootStrap

Django

一、中間件

django請求的生命週期

get/post
models
url/form
urls.py
views.py
模板
render

完整週期

get/post
models
url/form
中間件
urls.py
views.py
模板
render

可以看出中間件就是在實現請求之前,django或者我們自定義的對該請求的一些規則,而且是全局的,因爲中間件的觸發實在路由分發之前,比如某ip,某設爲不能訪問

django已經定義好的中間件

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

如果我們看這些類會發現,他們都繼承了一個類MiddlewareMixin

class MiddlewareMixin:
    def __init__(self, get_response=None):
        self.get_response = get_response
        super().__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):	# 如果有process_request方法就執行
            response = self.process_request(request)
        response = response or self.get_response(request)
        if hasattr(self, 'process_response'):	# 如果有process_response方法就執行
            response = self.process_response(request, response)
        return response
  • 所以,我們可以這樣定義自己的類
from django.utils.deprecation import MiddlewareMixin


class MyMW(MiddlewareMixin):
    def process_request(self, request):
        print('1:', 'mymdwa-->process_request')

    def process_response(self, request, response):
        print('1:', 'mymdwa-->process_response')
        return response	 # process_response是需要返回值的


class Mymw(MiddlewareMixin):
    def process_request(self, request):
        print('2:', 'mymdwa-->process_request')

    def process_response(self, request, response):
        print('2:', 'mymdwa-->process_response')
        return response

這裏需要注意的是:process_response是需要返回值的

  • 然後我們將自定義的中間件加入到settings中
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'app01.md.mdware.MyMW',		# 自定義中間件
    'app01.md.mdware.Mymw',		# 自定義中間件
]
  • 接着做一次get請求,我們可以看到打印結果:
    在這裏插入圖片描述
    Views是我在views函數中加入的print(‘Views’)

這裏反應的結果就是django先處理一個個request函數,如果一直通過,就會到達views函數,最後再將render的response逆序一層層地給中間件,最後傳遞到前端

request
request
request
request
response
response
response
response
GET/POST
middleware1
middleware2
middleware3
Views

可以發現這裏的request和response其實就是請求頭和相應結果

既然這個process_request(self, request)函數是用來處理請求頭的,那如果該請求沒有符合要求,我們就要給用戶返回一個錯誤頁面,或者請求結果

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse


class MyMW(MiddlewareMixin):
    def process_request(self, request):
    	if 允許請求:
        	print('1:', 'mymdwa-->process_request')
       	else:
        	return HttpResponse('403')

    def process_response(self, request, response):
        print('1:', 'mymdwa-->process_response')
        return response


class Mymw(MiddlewareMixin):
    def process_request(self, request):
    	if 允許請求:
        	print('2:', 'mymdwa-->process_request')
       	else:
        	return HttpResponse('403')

    def process_response(self, request, response):
        print('2:', 'mymdwa-->process_response')
        return response

在process_request()中加上未允許請求時的返回結果即可,1.7版本(目前最新2.11)之後,有一箇中間件未通過,返回錯誤結果後,後面的中間件將不再執行。

  • 其他

中間件的本質是,請求到達中間件時,先執行父類MiddlewareMixin的__call__方法,檢測是否有process_request()和process_response()方法,再跟着上面講述的順序執行。

所以我們也可以自定義這個父類,方便我們寫代碼。

我們自己可以寫一個類:

class MyMiddlewareMixin:
    def __init__(self, get_response=None):
        self.get_response = get_response
        super().__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'my_process_request'):
            response = self.process_request(request)
        response = response or self.get_response(request)
        if hasattr(self, 'my_process_response'):
            response = self.process_response(request, response)
        return response

這裏修改了父類的名字和請求函數的名字,以後我們的中間件類就可以繼承MyMiddlewareMixin,其中的函數名也可以改成my_process_request()my_process_response(),當然這裏只是舉一個例子,類名和函數名都可以根據自己習慣定義。

  • 中間件的另外幾個函數
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse


class MyMW(MiddlewareMixin):
    def process_request(self, request):
    	if 允許請求:
        	print('1:', 'mymdwa-->process_request')
       	else:
        	return HttpResponse('403')

    def process_response(self, request, response):
        print('1:', 'mymdwa-->process_response')
        return response
        
	def process_view(self, request, view_func, view_args, views_kwargs):
		"""
		在所有process_request函數執行完後,再從頭依次執行view函數
		request: 請求頭,
		view_func: views.py的對應處理函數,
		view_args: view_func()的參數
		view_kwargs: view_func()的參數
		"""
		print('1:', 'mymdwa-->process_view')

	def process_exception(self, request, exception):
		"""views.py的函數運行異常時逆序執行此函數"""
		return HttpResponse('請求出錯.')	# 遇到return後又從最後一箇中間件的process_response函數逆序執行,直到返回給前端

	def process_template_response(self, request, response):
		"""不常用"""
		pass

二、CSRF

跨站請求僞造
在第一次請求的時候django服務器會給前端返回一個csrf-cookies,以後post請求時必須帶上這個csrf才能通過這個csrfMiddleware,我們有幾種方式來實現:

  1. Form請求:在form表單下添加{% csrf_token %}
  2. ajax請求:給ajax配置請求頭:
// 預配置
$.ajaxSteup({
	beforeSend:funtin(xhr, setting){
		xhr.setRequestHeader('X-CSRFToken', $.cookie('csrf'));
	}
});
// ajax請求
$('.submit-btn').click({
	$.ajax({
		url: '/url/',
		type: 'POST',
		data: {'username': 'wolf'},
		success: function(arg){},
	})
})
  1. ajax請求:在發送的data數據中加上csrf:
// ajax請求
$('.submit-btn').click({
	$.ajax({
		url: '/url/',
		type: 'POST',
		data: {'username': 'wolf', 'csrfmiddlewaretoken': '{{ csrf_token }}'},
		success: function(arg){},
	})
})
  1. 因爲中間件是全局的,在views.py中可以設置裝飾器,設置某些函數必須通過csrf驗證,而全站不用
# 導入裝飾器
from django.views.decorators.csrf import csrf_exempt, csrf_protect
# 添加裝飾器,這個函數用,其他的不用
@csrf_protect
def login(request):
	from django.conf import settings	# django所有的配置
	print(settings.CSRF_HEADER_NAME)	# 
	return render(request, 'html')

@csrf_exempt	# 添加排除裝飾器,這個函數不用,其他的都用
def logout(request):
	return render(request, ''html)

一般用全站,只是少部分不用,可以使用@csrf_exempt

三、緩存

如果每次請求都去訪問數據庫,耗時將會很明顯,最好的解決方法就是用緩存:將某個views函數的返回值保存在內存(可以是其他機器)或者memcache中,設定時間內再有人來訪問,就直接從內存或redis中獲取,而不再去操作數據庫。優勢是快,劣勢是不能實時更新,我們永遠只能獲取到大約5分鐘以前的數據。

django的6種緩存方式

  1. 開發調試
  2. 內存
  3. 文件
  4. 數據庫
  5. memcache緩存(python-memcached模塊)
  6. memcache緩存(pylibmc模塊)

一般訪問量大,更新頻率低的適合緩存

1、配置
a、開發調試

CACHES = {
	'default': {
		'BACKEND': 'django.core.cache.backends.dummy.DummyCache',	# 引擎
		'TIMEOUT': 300,	# 緩存超時時間(默認300,None表示永久,0表示立即過期)
		'OPTIONS': {
			'MAX_ENTRIES': 300,		# 最大緩存數(默認300)
			'CULL_FREQUENCY': 3,	# 緩存達到最大後,刪除緩存的個數比例,默認爲3,即刪除1/3
		}
		'KEY_PREFIX': '',		# 緩存key的前綴,默認爲空
		'VERSION': 1, 		# 緩存key的版本,默認爲1
		'KEY_FUNCTION':函數名		# 生成key的函數(默認函數會生成爲:[前綴:版本:key])
	}
}

# 自定義key
def my_key()

b、內存

CACHES = {
	'default': {
		'BACKEND': 'django.core.cache.backends.dummy.DummyCache',	# 引擎
		'LOCATION': 'unique-snowflake',
		}
	}
# 其他配置同開發調試

c、文件

CACHES = {
	'default': {
		'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',	# 引擎
		'LOCATION': '/var/temp/cache',	# 文件路徑
		}
	}
# 其他配置同開發調試

d、數據庫

CACHES = {
	'default': {
		'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',	# 引擎
		'LOCATION': 'my_cache_table',	# 數據庫表明
		}
	}
# 其他配置同開發調試

e、Memcache緩存(python-memcached模塊)

CACHES = {
	'default': {
		'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',	# 引擎
		'LOCATION': '127.0.0.1:10001',	# 另外一臺電腦的ip: port,socket訪問
		}
	}
	
CACHES = {
	'default': {
		'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',	# 引擎
		'LOCATION': 'unix:/tmp/memcached.soc',	# 本機文件
		}
	}

CACHES = {
	'default': {
		'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',	# 引擎
		'LOCATION': [
			('172.168.1.1:9000',10# 後面數字爲權重,值越大,緩存到這臺機器的概率越大
			('172.168.1.2:9000',100)
			]	# 多臺機器
		}
	}
# 其他配置同開發調試

f、Memcache緩存(pylibmc模塊)

"""同上"""

2. 應用

先將上面的配置添加到settings.py文件中

a. 本頁緩存

from django.views.decorators.cache import cache_page
import time


@cache_page(10)		# 加入緩存裝飾器,這個views函數對應的頁面就會緩存,參數爲緩存時間/s
def cac(request):
    t = time.time()
    return HttpResponse(t)

b. 局部緩存

{% load cache %}


{% cache 5000 key %}	<!--緩存10秒,緩存文件爲-->
	緩存內容
{% cendcache %}

c. 全站緩存

  訪問進來時,爲了不訪問views函數直接返回緩存數據,我們就需要將檢測是否返回緩存的函數寫在我們前面所講的process_view()中間件函數中,而對於是否對此次請求返回數據,需要經過中間件的審覈,所以這個process_view()函數須要放在中間件的最後一步
  而對於緩存內容只是之前views.py函數所返回的response,我們是可能在中間件中對他進行了一些改變的,所以process_response()函數須要放在中間件的第一個位置
  這樣的兩個中間件django已經幫我們寫好了。

MIDDLEWARE = [
	'django.middleware.cache.UpdateCacheMiddleware',
	# 其他中間件
	'django.middleware.cache.FetchFromCacheMiddleware',
]

3. session使用緩存

在session配置中添加下面代碼即可

SESSION_CACHE_ALIAS = 'sessions'

四、信號

Django預留的hook

讓django在執行一些操作之前或者之後自動觸發一些事件,比如記錄數據庫的增刪改查操作,

  1. 內置信號
    a. hook名稱
Model signals
    pre_init                    # django的modal執行其構造方法前,自動觸發
    post_init                   # django的modal執行其構造方法後,自動觸發
    pre_save                    # django的modal對象保存前,自動觸發
    post_save                   # django的modal對象保存後,自動觸發
    pre_delete                  # django的modal對象刪除前,自動觸發
    post_delete                 # django的modal對象刪除後,自動觸發
    m2m_changed                 # django的modal中使用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          # 創建數據庫連接時,自動觸發

b. 導入方法:

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 my_func(sender,**kwargs):
	"""sender: django給我們提供的一些信息"""
    print('Do my func first')

reqyest_finished.connect(my_func)	# 即在請求結束後執行my_func()方法
  • 因爲在django項目開啓時就要註冊這些信號,所以寫在項目的__init__.py文件中,或者寫在其他py文件中,在__init__.py中導入
  • 一個hook可以添加多個函數
  1. 自定義信號
    a. 定義信號
import django.dispatch
my_signal = django.dispatch.Signal(providing_args=['x', 'y'])	# x,y參數自定義

b. 註冊信號

def callback(sender, **kwargs):
	print('my_signal')

my_signal.connect(callback)

c. 觸發信號
在自己寫的views等函數中觸發

from path import my_signal

my_signal.send(sender='name', x='x', y='y')

其實信號就相當於自定義的模塊,方便調用,當我們遇到可能需要靈活調用的功能時就可以選擇信號

五、BootStrap(模板) - 響應式+模板

集成了css、js的一個文件夾

BootStrap官網下載
全局css樣式

響應式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>響應式</title>
    <style>
    	/* 監聽瀏覽器寬度,當寬度小於700px時,改變對應的樣式
			這裏當瀏覽器寬度大於700px時,h1標籤爲黑色字體,寬度小於700px時,字體會變成紅色 */
        @media(max-width: 700px){
            .response-style{
                color: red;
            }
        }
    </style>
</head>
<body>
    <h1 class="response-style">響應式</h1>
</body>
</html>

柵格系統
JS插件

先引入jQuery再引入boostrapjs

–> 企業官網(延遲加載+組合搜索)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章