继文章:Django框架全面讲解(二)
七、中间件(MiddleWare)
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。
与mange.py在同一目录下的文件夹 wupeiqi/middleware下的auth.py文件中的Authentication类
中间件中可以定义五个方法,分别是:
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_template_response(self,request,response)
- process_exception(self, request, exception)
- process_response(self, request, response)
分析源码得知前二个方法是从前往后执行的,后三个方法是从后往前执行的
所以前两个方法是请求进来时要穿越的,而后三个方法是请求出去时要穿越的
一张图告诉你中间件的运行流程
7.1、 自定义中间件
7.1.1、创建中间件类
class Middle_Test(object):
def process_request(self,request):
pass
def process_view(self, request, callback, callback_args, callback_kwargs):
i =1
pass
def process_exception(self, request, exception):
pass
def process_response(self, request, response):
return response
7.1.2、注册中间件
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'sparks.middleware.auth.Middle_Test',
)
八、 Form
django中的Form一般有两种功能:
- 输入html
- 验证用户输入
Form
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from django import forms
from django.core.exceptions import ValidationError
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误')
class PublishForm(forms.Form):
user_type_choice = (
(0, u'普通用户'),
(1, u'高级用户'),
)
user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
attrs={'class': "form-control"}))
title = forms.CharField(max_length=20,
min_length=5,
error_messages={'required': u'标题不能为空',
'min_length': u'标题最少为5个字符',
'max_length': u'标题最多为20个字符'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': u'标题5-20个字符'}))
memo = forms.CharField(required=False,
max_length=256,
widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))
phone = forms.CharField(validators=[mobile_validate, ],
error_messages={'required': u'手机不能为空'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))
email = forms.EmailField(required=False,
error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
示例
def publish(request):
ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
if request.method == 'POST':
request_form = PublishForm(request.POST)
if request_form.is_valid():
request_dict = request_form.clean()
print request_dict
ret['status'] = True
else:
error_msg = request_form.errors.as_json()
ret['error'] = json.loads(error_msg)
return HttpResponse(json.dumps(ret))
利用Form还可以自动生成前端的input标签:
form.py
from app01 import models
from django import forms
class Form1(forms.Form):
user = forms.CharField(
widget=forms.TextInput(attrs={'class':'c1'}), # 给标签添加属性
error_messages={'required':'用户名不能为空'}, # 自定义错误输出
)
pwd = forms.CharField(max_length=4, min_length=2)
email = forms.EmailField(error_messages={'required':'邮箱不能为空', 'invalid':'邮箱格式错误'})
memo = forms.CharField(
widget=forms.Textarea()
)
# user_type_choice = (
# (0, '普通用户'),
# (1, '高级用户'),
# )
user_type_choice = models.BookType.objects.values_list("id", "caption")
# 这样并不能跟数据库实时同步,因为静态字段不更新
book_type = forms.CharField(
widget=forms.widgets.Select(choices=user_type_choice)
)
def __init__(self, *args, **kwargs):
super(Form1, self).__init__(*args, **kwargs)
# 让选项框跟数据库进行实时联动,解决上一行注释的问题
self.fields['book_type'] = forms.CharField(
widget=forms.widgets.Select(choices=models.BookType.objects.values_list("id", "caption"))
)
views.py
def form1(request):
if request.method == "POST":
# 获取请求做验证
f = Form1(request.POST)
if f.is_valid():
print(f.cleaned_data)
else:
pass
# print(f.errors['user'][0])
# print(f.errors['pwd'][0])
return render(request, "form1.html", {'error': f.errors, 'form':f})
else:
f = Form1()
return render(request, 'form1.html',{'form':f})
form1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.input-group{
position: relative;
padding: 23px;
}
.input-group input{
width: 200px;
display: inline-block;
}
.input-group span{
display: inline-block;
position: absolute;
height: 20px;
background-color:coral;
color: white;
bottom: 1px;
left: 22px;
width: 204px;
}
</style>
</head>
<body>
<div>
<form action="/form/" method="post">
<div class="input-group">
{# <input type="text" name="user"/>#}
{{ form.user }}
{% if error.user.0 %}
<span>{{ error.user.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{# <input type="text" name="pwd"/>#}
{{ form.pwd }}
{% if error.pwd.0 %}
<span>{{ error.pwd.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{{ form.email }}
{% if error.email.0 %}
<span>{{ error.email.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{{ form.memo }}
{% if error.memo.0 %}
<span>{{ error.memo.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{{ form.book_type }}
{% if error.book_type.0 %}
<span>{{ error.book_type.0 }}</span>
{% endif %}
</div>
<input type="submit" value="提交"/>
</form>
</div>
</body>
</html>
扩展:ModelForm
在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义
ModelForm
class AdminModelForm(forms.ModelForm):
class Meta:
model = models.Admin
#fields = '__all__'
fields = ('username', 'email')
widgets = {
'email' : forms.PasswordInput(attrs={'class':"alex"}),
}
九、 认证系统(auth)
auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组管理,并且可以和admin模块配合使用.
在INSTALLED_APPS中添加’django.contrib.auth’使用该APP, auth模块默认启用.
model
from django.contrib.auth.models import User
# 数据库中该表名为auth_user.
CREATE TABLE "auth_user" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"password" varchar(128) NOT NULL, "last_login" datetime NULL,
"is_superuser" bool NOT NULL,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL,
"email" varchar(254) NOT NULL,
"is_staff" bool NOT NULL,
"is_active" bool NOT NULL,
"date_joined" datetime NOT NULL,
"username" varchar(30) NOT NULL UNIQUE
)
新建用户
user = User.objects.create_user(username, email, password)
user.save()
# 不存储用户密码明文而是存储一个Hash值
认证用户
from django.contrib.auth import authenticate
user = authenticate(username=username, password=password)
# 认证用户的密码是否有效, 若有效则返回代表该用户的user对象, 若无效则返回None.
# 该方法不检查is_active标志位.
修改密码
user.set_password(new_password)
# 以下实例为先认证通过后才可以修改密码
user = auth.authenticate(username=username, password=old_password)
if user is not None:
user.set_password(new_password)
user.save()
登录
from django.contrib.auth import login
# login向session中添加SESSION_KEY, 便于对用户进行跟踪:
'login(request, user)'
# login不进行认证,也不检查is_active标志位
# 实例
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
退出登录
# logout会移除request中的user信息, 并刷新session
from django.contrib.auth import logout
def logout_view(request):
logout(request)
只允许登录的用户访问
@login_required修饰器修饰的view函数会先通过session key检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到login_url指定的位置.
若未指定login_url参数, 则重定向到settings.LOGIN_URL
from django.contrib.auth.decorators import login_required
@login_required(login_url='/accounts/login/')
def userinfo(request):
...
# settings 配置
LOGIN_URL = '/index/'
# views
@login_required
def userinfo(request):
...