django—中间件|CSRF|缓存|信号|BootStrap

本文详细介绍了Django框架中的中间件机制,包括自定义中间件的实现和作用。同时,讨论了CSRF保护的原理和实践方法,以及如何在Django中配置和使用缓存来提高性能。此外,还介绍了BootStrap在Django模板中的应用,尤其是响应式设计和模板布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

–> 企业官网(延迟加载+组合搜索)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值