17 django中间件
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>
夕闻道不如朝闻道