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 }
12 django组件中间件\middleware\middleware\settings.py
from django.urls import path
from middle_app01 import views

urlpatterns = [
    path('index/', views.index),
    path('login/', views.login),
    path('secret/', views.secret),
]
12 django组件中间件/middleware/middle_app01/urls.py
 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/myforms.py

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>

 

posted @ 2019-08-19 16:31  毛斯钢  阅读(214)  评论(0编辑  收藏  举报