django中间件
中间件就是中间商,你从厂家买东西,经过中间商的协调,拿到自己想要的东西,显然方便了很多,但是也存在一定性能问题,因为不是直接和服务器打交道,而是通过一层层的中间商。
直接上代码,包含两个应用


1 """
2 Django settings for middleware project.
3
4 Generated by 'django-admin startproject' using Django 2.2.3.
5
6 For more information on this file, see
7 https://docs.djangoproject.com/en/2.2/topics/settings/
8
9 For the full list of settings and their values, see
10 https://docs.djangoproject.com/en/2.2/ref/settings/
11 """
12
13 import os
14
15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17
18
19 # Quick-start development settings - unsuitable for production
20 # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
21
22 # SECURITY WARNING: keep the secret key used in production secret!
23 SECRET_KEY = '*k9n@iw!c6dsh_wdw!tc+v^4d(_k!v_(^j-g$^j@^e=#$w1vr8'
24
25 # SECURITY WARNING: don't run with debug turned on in production!
26 DEBUG = True
27
28 ALLOWED_HOSTS = []
29
30
31 # Application definition
32
33 INSTALLED_APPS = [
34 'django.contrib.admin',
35 'django.contrib.auth',
36 'django.contrib.contenttypes',
37 'django.contrib.sessions',
38 'django.contrib.messages',
39 'django.contrib.staticfiles',
40 'middle_app01',
41 ]
42
43 MIDDLEWARE = [
44 'django.middleware.security.SecurityMiddleware',
45 'django.contrib.sessions.middleware.SessionMiddleware',
46 'django.middleware.common.CommonMiddleware',
47 'django.middleware.csrf.CsrfViewMiddleware',
48 'django.contrib.auth.middleware.AuthenticationMiddleware',
49 'django.contrib.messages.middleware.MessageMiddleware',
50 'django.middleware.clickjacking.XFrameOptionsMiddleware',
51 'middlewares.AuthLimit',
52 'middlewares.IpLimitMiddleWare',
53 'middlewares.MdOne',
54 'middlewares.MdTwo',
55 ]
56
57 ROOT_URLCONF = 'middleware.urls'
58
59 TEMPLATES = [
60 {
61 'BACKEND': 'django.template.backends.django.DjangoTemplates',
62 'DIRS': [os.path.join(BASE_DIR, 'templates')],
63 'APP_DIRS': True,
64 'OPTIONS': {
65 'context_processors': [
66 'django.template.context_processors.debug',
67 'django.template.context_processors.request',
68 'django.contrib.auth.context_processors.auth',
69 'django.contrib.messages.context_processors.messages',
70 ],
71 },
72 },
73 ]
74
75 WSGI_APPLICATION = 'middleware.wsgi.application'
76
77
78 # Database
79 # https://docs.djangoproject.com/en/2.2/ref/settings/#databases
80
81 # DATABASES = {
82 # 'default': {
83 # 'ENGINE': 'django.db.backends.sqlite3',
84 # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
85 # }
86 # }
87
88
89 # Password validation
90 # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
91
92 AUTH_PASSWORD_VALIDATORS = [
93 {
94 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
95 },
96 {
97 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
98 },
99 {
100 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
101 },
102 {
103 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
104 },
105 ]
106
107
108 # Internationalization
109 # https://docs.djangoproject.com/en/2.2/topics/i18n/
110
111 LANGUAGE_CODE = 'en-us'
112
113 TIME_ZONE = 'UTC'
114
115 USE_I18N = True
116
117 USE_L10N = True
118
119 USE_TZ = True
120
121
122 # Static files (CSS, JavaScript, Images)
123 # https://docs.djangoproject.com/en/2.2/howto/static-files/
124
125 STATIC_URL = '/static/'
126 STATICFILES_DIRS = [
127 os.path.join(BASE_DIR, 'statics')
128 ]
129
130 LOGIN_URL = '/app01/login/'
131
132 DATABASES = {
133 'default': {
134 'ENGINE': 'django.db.backends.mysql',
135 'NAME':'auth',# 要连接的数据库,连接前需要创建好
136 'USER':'root',# 连接数据库的用户名
137 'PASSWORD':'root',# 连接数据库的密码
138 'HOST':'127.0.0.1',# 连接主机,默认本级
139 'PORT':3306 # 端口 默认3306
140 }
141 }
142
143 LOGGING = {
144 'version': 1,
145 'disable_existing_loggers': False,
146 'handlers': {
147 'console':{
148 'level':'DEBUG',
149 'class':'logging.StreamHandler',
150 },
151 },
152 'loggers': {
153 'django.db.backends': {
154 'handlers': ['console'],
155 'propagate': True,
156 'level':'DEBUG',
157 },
158 }
159 }

from django.urls import path
from middle_app01 import views
urlpatterns = [
path('index/', views.index),
path('login/', views.login),
path('secret/', views.secret),
]

1 from django import forms
2 from django.forms import widgets
3 from django.core.exceptions import ValidationError
4 from django.contrib.auth.models import User
5
6
7 name_widget = widgets.TextInput(attrs={'class':'form-control'})
8 pwd_widget = widgets.PasswordInput(attrs={'class':'form-control'})
9
10
11 class Form(forms.Form):
12 name = forms.CharField(min_length=4, max_length=16, widget=name_widget, label='用户名')
13 pwd = forms.CharField(min_length=4, max_length=16, widget=pwd_widget, label='密码')
14 email = forms.EmailField(widget=name_widget, label='邮箱')
15
16 def clean_name(self):
17 val = self.cleaned_data.get('name')
18 res = User.objects.filter(username=val).exists()
19 if not res:
20 return val
21 else:
22 raise ValidationError('用户名已存在!')
23
24
25 class LoginForm(forms.Form):
26 name = forms.CharField(min_length=4, max_length=16, widget=name_widget, label='用户名')
27 pwd = forms.CharField(min_length=4, max_length=16, widget=pwd_widget, label='密码')
12 django组件中间件/middleware/middle_app01/views.py 视图函数
1 from django.shortcuts import render, HttpResponse, redirect
2 from django.contrib import auth
3 from middle_app01.myforms import LoginForm
4
5 # Create your views here.
6
7
8 def index(request):
9 print('----------------------> 视图函数给出的真实响应')
10 return render(request, 'index.html')
11
12 # 视图函数出错 测试 process_exception
13 # return render(request, 'indexasdfadf.html')
14
15
16 def secret(request):
17 return render(request, 'secret.html',locals())
18
19
20 def login(request):
21 if request.method == 'POST':
22 form = LoginForm(request.POST)
23 if form.is_valid():
24 print(form.cleaned_data)
25 username = form.cleaned_data.get('name')
26 pwd = form.cleaned_data.get('pwd')
27 user = auth.authenticate(username=username, password=pwd)
28 if user:
29 auth.login(request, user)
30 next_url = request.GET.get('next', '/app01/index')
31 return redirect(next_url)
32 else:
33 error = '用户名或密码错误!'
34 return render(request, 'login.html', locals())
35 else:
36 print(form.cleaned_data)
37 print(form.errors)
38 return render(request, 'login.html', locals())
39 else:
40 form = LoginForm()
41 return render(request, 'login.html', locals())
12 django组件中间件\middleware\middlewares.py 自己定义的中间件
1 from django.utils.deprecation import MiddlewareMixin
2 from django.shortcuts import HttpResponse, redirect
3 from middleware import settings
4 import time
5
6
7 '''
8 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。
9 因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。
10 如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
11 可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。
12 '''
13
14
15 class MdOne(MiddlewareMixin):
16
17 # 当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,
18 # 在依次穿过中间件,这个时候是process_response,最后返回给请求者。
19 def process_request(self, request):
20 ip_black_lis = ['127.0.0.1']
21 print("----------------------> 请求到达MdOne.process_request")
22 ip = request.META.get('REMOTE_ADDR')
23 # 请求到达中间件process_request,如果process_request函数有return,那么将不再继续按正常的流程走到视图函数
24 # 而是直接返回数据给客户端(),如之前是 A->B->C->视图函数 假如B中发生return,直接返回数据 B->A->客户端
25 # if ip in ip_black_lis:
26 # return HttpResponse('ip在黑名单内,请求中断!')
27
28 # 当最后一个中间的process_request到达路由关系映射之后,返回到中间件1的process_view,然后依次往下,到达views函数。
29 # 最后通过process_response依次返回到达用户。
30 def process_view(self, request, callback, callback_args, callback_kwargs):
31 print("----------------------> 请求到达MdOne.process_view")
32 # process_view如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行。
33 # return HttpResponse('ojbk!')
34
35 # 还可以直接调用视图函数
36 # response = callback(request, *callback_args, **callback_kwargs)
37 # return response
38
39 # 当视图函数报错时,执行这个函数,注意这里已经到达了视图函数,开始网上冒泡,所以这里先答应 MdTwo的process_exception
40 # HttpResponse('内部有误!') 返回给客户端,如果在 MdTwo 中有返回,则跳过 MdOne 的 MdTwo的process_exception 直接到 MdTwo的process_response
41 def process_exception(self, request, exception):
42 print("----------------------> 当视图函数出错MdOne.process_exception")
43 # return HttpResponse('内部有误!')
44
45 def process_response(self, request, response):
46 print("----------------------> 返回达到MdOne.process_response")
47 return response
48
49
50 class MdTwo(MiddlewareMixin):
51
52 def process_request(self, request):
53 print("----------------------> 请求到达MdTwo.process_request")
54
55 def process_view(self, request, callback, callback_args, callback_kwargs):
56 print("----------------------> 请求到达MdTwo.process_view")
57
58 def process_exception(self, request, exception):
59 print("----------------------> 当视图函数出错MdTwo.process_exception")
60 return HttpResponse('内部有误!')
61
62 def process_response(self, request, response):
63 print("----------------------> 返回达到MdTwo.process_response")
64 return response
65
66
67 ip_pool = {}
68 # Django中间件限制用户每分钟访问次数不超过10次,一般用于反爬
69 class IpLimitMiddleWare(MiddlewareMixin):
70
71 def time_filter(self, val):
72 return time.time() - val < 60
73
74 def process_request(self, request):
75 ip = request.META.get('REMOTE_ADDR')
76 if ip_pool.get(ip):
77 ip_pool[ip] = list(filter(self.time_filter, ip_pool[ip]))
78 ip_pool[ip].append(time.time())
79 else:
80 ip_pool[ip] = [time.time()]
81 print(ip_pool)
82 if len(ip_pool[ip]) > 10:
83 return HttpResponse("频繁访问,请稍后再试!")
84
85
86 # URL访问过滤
87 # 如果用户访问的是login视图(放过)
88 # 如果访问其他视图,需要检测是不是有session认证,已经有了放行,没有返回login,这样就省得在多个视图函数上写装饰器了!
89 class AuthLimit(MiddlewareMixin):
90
91 def process_request(self, request):
92 path = request.path
93 print(path)
94 if path != settings.LOGIN_URL and not request.user.is_authenticated:
95 new_path = settings.LOGIN_URL + '?next=' + path
96 return redirect(new_path)
12 django组件中间件/middleware/templates/login.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>login</title>
6 <link rel="stylesheet" href="/static/bootstrap.min.css">
7 </head>
8 <body>
9
10 <div class="container">
11 <div class="row">
12 <div class="col-md-6 col-md-offset-3">
13 <h4>登录</h4>
14 <form action="" method="post">
15 {% csrf_token %}
16 {% for field in form %}
17 <div class="form-group">
18 <label for="">{{ field.label }}</label>
19 {{ field }}
20 <span class="pull-right" style="color: red">{{ field.errors.0 }}</span>
21 </div>
22 {% endfor %}
23 <input type="submit" class="btn btn-success">
24 <span class="pull-right" style="color: red">{{ error }}</span>
25 </form>
26 </div>
27 </div>
28 </div>
29
30 </body>
31 </html>
