第06章 上下文处理器与中间件
什么是上下文处理器?
上下文处理器是可以返回一些数据,在全局模板中都可以使用。
比如登录后的用户信息,在很多页面中都需要使用,那么我们可以放在上下文处理器中,就没有必要在每个视图函数中都返回这个对象。
功能:用于模板中,返回一些数据。
django中,在settings.TEMPLATES.OPTIONS.context_processors
中,有很多内置的上下文处理器。这些上下文处理器的作用如下:
django.template.context_processors.debug
: 增加一个debug和sql_queries变量。在模板中就可以通过他来查看到一些数据库查询。django.template.context_processors.request
:增加一个request变量。这个request变更也就是在视图函数的第一个参数。django.template.context_processors.auth
:django有内置的用户系统,这个上下文处理器会增加一个user对象。django.template.context_processors.messages
:增加五个messages变量。
自定义上下文处理器:
- 定义上下文处理器
- 注册上下文处理器
# 1.定义上下文管理器
from .models import User
def front_user(request):
user_id = request.session.get('user_id)
context = {}
if user_id:
try:
user = User.object.get(pk=user_id)
context['front_user'] = user
except:
pass
return context
# 2. 注册上下文处理
# setttings.py
TEMPLATES = [{
...,
'context_processors': [
...,
'front.context_precessors.front_user'
]
}]
django自带上下文处理器
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
中间件
什么是中间件 middleware
middleware, 意即过滤器,使用的是装饰器技术
中间件用途
中间件是在request和response处理过程中的一个插件。比如在request到达视图函数之前,我们可以使用中间件来做一些相关的事情,比如:
- 可以判断当前这个用户有没有登录,如果登录了,就绑定一个user对象到request上。
- 也可以在response到达浏览器之前,做一些相关的操作,
- 比如想要统一在response上设置一些cookie信息等。
自定义中间件
中间件的位置没有规定。只要放到项目当中即可。一般分为两种情况,
- 如果中间件是属于某个app的,那么可以在这个app下面创建一个python文件来存放这个中间件,
- 也可以专门创建的一个python包,用来存放本藏在的所有中间件。
创建中间件有两种方式,
- 使用函数
- 使用类
使用函数的中间件
def simple_middleware(get_response):
# 这个中间件初始化的代码
def middleware(request):
# request 到达view之前的执行代码
response = get_response(request)
# response 到达浏览器之前的执行代码
return response
return middleware
使用类的中间件
class FrontUserMiddleware:
def __init__(self, get_response):
# 这个中间件初始化的代码
self.get_response = get_response
def __call__(self, request):
print("request 到达view之前的执行代码")
user_id = request.session.get('user_id')
if user_id:
try:
user = User.objects.get(pk=user_id)
request.front_user = user
except:
request.front_user = None
else:
request.front_user = None
response = self.get_response(request)
# response 到达浏览器之前的执行代码
return response
项目中的中间件
from django.conf import settings
from ipware.ip import get_ip
from server_side_piwik.tasks import record_analytic
class PiwikMiddleware(object):
""" Record every request to piwik """
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
SITE_ID = getattr(settings, 'PIWIK_SITE_ID', None)
if SITE_ID:
ip = get_ip(request)
keys_to_serialize = [
'HTTP_USER_AGENT',
'REMOTE_ADDR',
'HTTP_REFERER',
'HTTP_ACCEPT_LANGUAGE',
'SERVER_NAME',
'PATH_INFO',
'QUERY_STRING',
]
data = {
'HTTPS': request.is_secure()
}
for key in keys_to_serialize:
if key in request.META:
data[key] = request.META[key]
user_id = None
if getattr(settings, 'PIWIK_TRACK_USER_ID', None) and request.user and request.user.pk:
user_id = request.user.pk
record_analytic.delay(data, ip, user_id)
return response
内置中间件
- django.middleware.common.CommonMiddleware:通用中间件,作用如下:
- 限制 settings.DISALLOWED_USER_AGENTS 中指定的请求来访问本网站(限制蜘蛛)
import re
DISALLOWED_USER_AGENTS = [
re.compile(r'^\s$|^$'), # 所有空白符或者空字符
re.compile(r'.*PhantomJS.*') # PhantomJS
]
- 给url添加最后的斜杠
- django.middleware.gzip.GZipMiddleware:response响应数据压缩(response>=200字符才会压缩)
- django.contrib.messages.middleware.MessageMiddleware:消息处理相关的中间件
- django.middle.security.SecurityMiddleware:安全处理,如设置XSS防御的请求头,做http转https等
- django.contrib.sessions.middleware.SessionMiddleware:给request添加一个处理好的session对象
- django.contrib.auth.middleware.AuthenticationMiddleware:给request添加一个user对象
- django.middleware.csrf.CsrfViewMiddleware:CSRF保护
- django.middleware.clickjacking.XFrameOptionsMiddleware:做clickjacking保护
- 缓存中间件:用来缓存一些页面
- django.middleware.cache.UpdateCacheMiddleware
- django.middleware.cache.FetchFormCacheMiddleware
clickjacking: 指攻击者在自己的病毒网站上添加诱惑性的按钮,使用iframe技术将受攻击网站(比如银行)加载到自己的网站上去,并将其设置为透明;诱惑用户点击执行受攻击的网站操作。
中间件放置顺序
- Securitywiddleware:应该放到最前面。因为这个中间件并不需要依赖任何其他的中间件。如果你的网站同时支持http协议和https协议,并且你想让用户在使用http协议的时候重定向到https协议,那么就没有必要让他执行下面一大串中间件再重定向,这样效率更高。
- UpdateCacheMiddleware:应该在SessionMiddleware,GZipMiddleware,LocaleMiddleware之前。
- GZipMiddleware。
- ConditionalGetMiddleware。
- SessionMiddleware。
- LocaleMiddleware。
- CommonMiddleware。
- CsrfViewliddleware。
- AuthenticationMiddleware。
- MessageMiddleware。
- FetchFromCacheMiddleware。
- FlatpageFallbackMiddleware。
- RedirectFallbackMiddleware。
信号
Django 包含一个“信号调试程序”,它有助于在框架中的其他位置发生操作时通知分离的其他部分程序。也就是说:信号允许某些发送者通知一组接收器已经发生了某些动作。当许多代码可能对同一事件感兴趣时,它们特别有用。
django 内置了一组信号,让用户代码可以通过django自己通知某些操作。包括
信号 | 说明 |
---|---|
django.db.models.signals.pre_save |
|
django.db.models.signals.post_save |
模型调用 save() 之前/之后发送 |
django.db.models.signals.pre_delete |
|
django.db.models.signals.post_delete |
调用模型的models.delete() 或者 queryset.delete() 方法之前/之后发送 |
django.core.signals.request_started |
|
django.core.signals.request_finished |
django启动/完成http请求时发送 |
django.db.models.signals.m2m_changed |
MangToMangField更改模型时发送 |
文档地址:
https://docs.djangoproject.com/zh-hans/2.0/topics/signals/
https://docs.djangoproject.com/zh-hans/2.0/ref/signals/
监听信号
使用 Signal.conect()
注册接收者函数,接收一个信号;当信号发生时,会调用接收者函数。
Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)
parameters:
receiver - 回调函数连接此信号
sender - 指定发送者
weak - Django在默认情况下将信号处理程序存储为弱引用。因此,如果您的接收器是一个本地函数,那么它可能是垃圾收集的。为了防止这种情况发生,当您调用signal.connect()方法时,传递 weak=False。
dispatch_uid - 在可能发送重复信号的情况下,信号接收器的唯一标识符。有关更多信息,请参见防止重复信号 https://docs.djangoproject.com/zh-hans/2.0/topics/signals/#preventing-duplicate-signals。
监听信号方法:
定义接收器
连接接收器
连接到特定发送者发送的信号
防止重复信号
定义和发送信号
定义信号
发送信号
断开信号