django中间件的使用
1.创建中间件
在django项目的settings模块中,有一个MIDDLEWARE_CLASSES变量,其中每一个元素就是一个中间件。中间件其实就是django中的一个类,在请求到来和结束后,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',
]
我们在做登录注册功能时一般都会做一个中间件,当用户登录失败时就会返回登录页面。这样就不用在每个方法中验证cooki了(不要重复代码)。
中间件一般放在utils文件中(大家都这么做),我们接着前两天的登录注册功能的代码改写,首先在项目文件下创建一个utils文件夹,在其下面写中间件。
class AuthMiddleWare(MiddlewareMixin):
def process_request(self, request):
# 同意验证登录
# return None 或者不写
if request.path == '/uauth/login/' or request.path == '/uauth/regist/':
return None
ticket = request.COOKIES.get('ticket')
if not ticket:
return HttpResponseRedirect('/uauth/login/')
users = Users.objects.filter(u_ticket=ticket)
if not users:
return HttpResponseRedirect('/uauth/login/')
request.user = users[0]
上面代码中的process_request
是中间件的一种方法。中间件有五种方法,如下图:
2.注册中间件
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’,
‘utils.UserAuthMiddleWare.AuthMiddleWare’,
]
3.方法改写
在创建中间件过后就不需要在方法中对cookie进行验证了,所以我们对方法进行改写:
def regist(request):
if request.method == 'GET':
return render(request, 'register.html')
if request.method == 'POST':
# 注册
name = request.POST.get('name')
password = request.POST.get('password')
password = make_password(password)
Users.objects.create(u_name=name,
u_password=password)
return HttpResponseRedirect('/uauth/login/')
def login(request):
if request.method == 'GET':
return render(request, 'day6_login.html')
if request.method == 'POST':
# 如果登录成功,绑定参数到cookie中,set_cookie
name = request.POST.get('name')
password = request.POST.get('password')
if Users.objects.filter(u_name=name).exists():
user = Users.objects.get(u_name=name)
if check_password(password, user.u_password):
ticket = ''
s = 'qwertyuioplkjhgfdsazxcvbnm1234567890'
for i in range(15):
# 获取十五位随机字符串
ticket += random.choice(s)
now_time = int(time.time())
# time.time()表示从1970.1.1到现在的秒数
ticket = 'TK_' + ticket + str(now_time) # 加上时间戳ticket就永远不会重复
# 绑定令牌到cookie里面
response = HttpResponseRedirect('/stu/index/')
# max_age 存活时间/s
response.set_cookie('ticket', ticket, max_age=600000000)
# 存在服务段
user.u_ticket = ticket
user.save()
return response
else:
return render(request, 'day6_login.html', {'password': '用户密码错误'})
else:
return render(request, 'day6_login.html', {'name': '用户不存在'})
def logout(request):
if request.method == 'GET':
response = HttpResponseRedirect('/uauth/login/')
response.delete_cookie('ticket')
return response
另外我们在提交表单的时候要在表单里面加上{% csrf_token %}
,它提供了不被跨站攻击的保护。
4.加载静态文件
我们可以通过加载静态文件来对我们的登录注册页面进行渲染,获得更好的用户体验。
首先我们要创建静态文件夹,在这个文件夹中要包含所有对页面进行渲染需要的元素。(我这里用别人写好的)
其次我们要在项目文件下的setting中进行改写,使页面能读取整个静态文件。
#配置静态文件
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
这样我们再次输入登录的地址就会看到一个好看的页面了
5.上传图片
我们在注册网站时,有的网站会让我们上传图片,比如头像。那么这是怎么实现的呢。
首先我们在写注册信息时就要写入上传图片的方法。
def addStuInfo(request, stu_id):
if request.method == 'GET':
return render(request, 'addStuInfo.html', {'stu_id': stu_id})
if request.method == 'POST':
stu_id = request.POST.get('stu_id')
addr = request.POST.get('addr')
# 添加头像图片
img = request.FILES.get('img')
StudentInfo.objects.create(i_addr=addr, s_id=stu_id, i_image=img)
return HttpResponseRedirect('/stu/index/')
然后在写页面的时候也要添加上传图片的选项。
<form action="" method="POST" enctype="multipart/form-data">
<input type="hidden" value="{{ stu_id }}" name="stu_id">
地址:<input type="text" name="addr">
图像:<input type="file" name="img">
<input type="submit" value="提交">
{% csrf_token %}
</form>
注意这里为了不让别人也能提交你的表单,我们在每个表单下面都要写{% csrf_token %}
。
6.创建日志
再做实际项目时,无论是在开发调试的时候,还是上线为用户提供服务以后,都需要保留下一些运行当中必要的信息用于日后的维护和故障的定位。Django中使用Python内建的logging模块做日志的收集。
首先,我们需要创建存放日志的文件夹
LOG_PATH = os.path.join(BASE_DIR, 'log')
# 如果没有log这个文件夹就自动创建
if not os.path.isdir(LOG_PATH):
os.mkdir(LOG_PATH)
其次就是日志的格式及其信息处理
LOGGING = {
'version': 1, # 必须写
# disable_existing_loggers表示弃用已经存在的日志,True表示弃用,False表示不弃用。
'disable_existing_loggers': False, # 不禁用log功能
# 格式化日志
'formatters': {
'default': {
'format': '%(levelname)s %(funcName)s %(asctime)s %(message)s'
},
'simple': {
'format': '%(levelname)s %(asctime)s %(message)s'
}
},
# 处理信息
'handlers': {
'stu_handlers': {
'level': 'DEBUG',
# 指定日志文件指定为5M,超过5M重新备份,然后写入新的日志文件
'class': 'logging.handlers.RotatingFileHandler',
'maxBytes': 5 * 1024 * 1024,
# 文件地址
'filename': '%s/stu_log.txt' % LOG_PATH,
'formatter': 'default'
},
'uauth_handlers': {
'level': 'DEBUG',
# 指定日志文件指定为5M,超过5M重新备份,然后写入新的日志文件
'class': 'logging.handlers.RotatingFileHandler',
'maxBytes': 5 * 1024 * 1024,
# 文件地址
'filename': '%s/uauth_log.txt' % LOG_PATH,
'formatter': 'simple'
}
},
最后传入要处理的信息
'loggers': {
'stu': {
'handlers': ['stu_handlers'],
'level': 'INFO'
},
'auth': {
'handlers': ['uauth_handlers'],
'level': 'INFO'
}
},
'filters': {
}
}
在配置好setting之后,进入到方法中,对需要记录日志的方法写上记录信息。
我这里演示在进入stu/index/页面是记录日志
import logging
logger = logging.getLogger('stu')
def index(request):
if request.method == 'GET':
stuinfos = StudentInfo.objects.all()
logger.info('url:%s method: %s 获取学生信息成功' % (request.path, request.method))
return render(request, 'index.html', {'stuinfos': stuinfos})
这样在每次进入stu/index/页面就会有一个存放在log文件夹下的stu_log.txt的记录日志,里面记录了每次对方法进行操作时的信息。
20 index 2018-05-03 15:29:59,456 url:/stu/index/ method: GET 获取学生信息成功
20 index 2018-05-03 15:34:19,590 url:/stu/index/ method: GET 获取学生信息成功
20 addStuInfo 2018-05-03 15:35:47,678 url:/stu/addstuInfo/12/ method: POST 添加学生信息成功
20 index 2018-05-03 15:35:47,881 url:/stu/index/ method: GET 获取学生信息成功
INFO index 2018-05-03 16:04:52,287 url:/stu/index/ method: GET 获取学生信息成功
INFO index 2018-05-03 16:06:50,751 url:/stu/index/ method: GET 获取学生信息成功
最后说明的是log记录的日志分为四个level:
critical>error>warning>info>dbug
一般来说做运维和开发人员对critical和error特别重视的。