05-django入门-类视图和中间件
1类视图
1.1类视图概念引入
视图函数与类视图的区别
以函数的方式定义的视图称为函数视图,函数视图便于理解。
但是遇到一个视图对应的路径提供了多种不同HTTP请求方式的支持时,
便需要在一个函数中编写不同的业务逻辑,代码可读性与复用性都不佳。
- 1.1案例使用:
def register(request):
"""处理注册"""
# 获取请求方法,判断是GET/POST请求
if request.method == 'GET':
# 处理GET请求,返回注册页面
return render(request, 'register.html')
else:
# 处理POST请求,实现注册逻辑
return HttpResponse('这里实现注册逻辑')
url
path('index2/',views.index2 ),
class RegisterView(View):
"""
这是定义类视图
"""
# 这个类里面定义的方法不是自定义的是请求方法
def get(self, request):
return render(request,'index3.html')
def post(self, request):
# 获取用户名
username = request.POST.get('username')
print(username)
from django.http import JsonResponse
return JsonResponse({'username':username})
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="#" method="post">
username: <input type="text" id="username" name="username"><br>
password: <input type="password" id="password" name="password" ><br>
register: <button type="submit">注册</button>
register: <button type="submit" ><a href="{% url 'index3' %}" >注册</a> </button>
</form>
</form>
</body>
</html>
-
1.2使用类视图定义函数
在 django中使用定义类的方式来定义一个视图 ,称之为类视图 使用类视图可以将视图对应的不同请求方式以类中不同方法来区别定义 类视图的好处: 代码可读性好 类视图相对于函数视图有更高的复用性, 如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可. from django.views.generic import View class RegisterView(View): """类视图:处理注册""" def get(self, request): """处理GET请求,返回注册页面""" return render(request, 'register.html') def post(self, request): """处理POST请求,实现注册逻辑""" return HttpResponse('这里实现注册逻辑') urlpatterns = [ # 视图函数:注册 # path('register/', views.register, name='register'), # 类视图:注册 path('register/', views.RegisterView.as_view(), name='register'), ]
- 1.3类视图的原理
```Python
@classonlymethod
def as_view(cls, **initkwargs):
"""
Main entry point for a request-response process.
"""
...省略代码...
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 调用dispatch方法,按照不同请求方式调用不同请求方法
return self.dispatch(request, *args, **kwargs)
...省略代码...
# 返回真正的函数视图
return view
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
- 1.4扩展(不需要掌握 )
- 类视图使用装饰器
- 自定义一个装饰器用来做调用
def my_decorator(func):
def wrapper(request, *args, **kwargs):
print('自定义装饰器被调用了')
print('请求路径%s' % request.path)
return func(request, *args, **kwargs)
return wrapper
class DemoView(View):
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
# 此方法为在URL配置中装饰, 此种方式会为类视图中的所有请求方法都加上装饰器行为
urlpatterns = [
path('demo/', my_decorate(DemoView.as_view()))
]
# 在类视图中装饰,在类视图中使用为函数视图准备的装饰器时,不能直接添加装饰器,需要使用method_decorator将其转换为适用于类视图方法的装饰器
# 为全部请求方法添加装饰器
from django.utils.decorators import method_decorator
class DemoView(View):
@method_decorator(my_decorator)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
from django.utils.decorators import method_decorator
# 为特定请求方法添加装饰器
class DemoView(View):
@method_decorator(my_decorator)
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
为什么需要使用method_decorator呢
为函数视图准备的装饰器,其被调用时,第一个参数用于接收request对象,
而类视图中请求方法被调用时,传入的第一个参数不是request对象,
而是self 视图对象本身,第二个位置参数才是request对象
所以如果直接将用于函数视图的装饰器装饰类视图方法,会导致参数传递出现问题。
method_decorator的作用是为函数视图装饰器补充第一个self参数,以适配类视图方法。
2中间件
什么是中间件?
Django中的中间件是一个轻量级、底层的插件系统
可以用来做什么?
Django 中间件是修改 Django request 或者 response 对象的钩子,可以理解为是介于 HttpRequest 与 HttpResponse 处理之间的一道处理过程。
传话人,中间商。能够介入请求与响应的流程之间,可以对请求对象或者响应对象进行修改,修改了之后在传到下一个流程之中进程处理;同时中间件也可以提升项目的一个安全性。同时中间件的作用范围是整个请求响应的流程。
**调用的过程->看做递归的形式->当中间件在配置文件中的中间件列表中不是最后一个元素的时候,此时get_response为指向下一个中间件;当中间件在配置文件中的中间件列表中是最后一个元素的时候,此时get_response可直接看做一个视图**
自定义中间件:以闭包的形式存在
##### 中间件开发流程:
1. 在项目中创建一个用于存放中间件代码的文件夹
2. 在此文件夹中进行中间件的设计
3. 中间设计好了之后,需要将自定义的中间件注册到项目之中
-
自带中间件介绍
# django中的中间件 底层的插件系统 MIDDLEWARE = [ # 主要是针对安全访问处理,就是把http请求重定向到https请求 'django.middleware.security.SecurityMiddleware', # 在Django中我们用的request.session就是在process_request中进行处理的, # 根据我们在settings中配置的SESSION_COOKIE_NAME变量, # 从cookies中获取对应的值,从表中查询出session值,创建session对象, # 赋值给request_session对象。 'django.contrib.sessions.middleware.SessionMiddleware', # 检测是否允许浏览器类型 'django.middleware.common.CommonMiddleware', #跨域请求伪造中间件。加入这个中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击 # 'django.middleware.csrf.CsrfViewMiddleware', # 从用户表中查询对应主键,得到用户对象,将其付给request.user 'django.contrib.auth.middleware.AuthenticationMiddleware', # Django的消息框架,主要是向目标中推送消息内容 'django.contrib.messages.middleware.MessageMiddleware', # 防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现 'django.middleware.clickjacking.XFrameOptionsMiddleware', # 中间件的执行顺序 先调用最下面的中间件,再先从上往下执行,再从下往上 ]
- 2.1案例自定义中间件
1在子应用文件下新建(自定义).py文件(middlewarse.py)
# 1在子应用文件下创建(自定义).py文件
# 2 自定义中间件
def outer1(fuc):
print('调用前1')
def inner(*args,**kwargs):
print('执行前1')
data = fuc(*args,**kwargs)
print('执行后1')
return data
return inner
def outer2(fuc):
print('调用前2')
def inner(*args,**kwargs):
print('执行前2')
data = fuc(*args,**kwargs)
print('执行后2')
return data
return inner
def outer3(fuc):
print('调用前3')
def inner(*args,**kwargs):
print('执行前3')
data = fuc(*args,**kwargs)
print('执行后3')
return data
return inner
- 2.2 在setting.py中的MIDDLEWARE[] 中添加中间件的路径
'users.middlewarse.outer1', # 自定义中间件
'users.middlewarse.outer2', # 自定义中间件
'users.middlewarse.outer3', # 自定义中间件
中间件可以定义四个方法,分别是:
process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_exception(self, request, exception)
process_response(self, request, response)
from django.utils.deprecation import MiddlewareMixin
process_request 方法
process_request 方法有一个参数 request,这个 request 和视图函数中的 request 是一样的。
process_request 方法的返回值可以是 None 也可以是 HttpResponse 对象。
返回值是 None 的话,按正常流程继续走,交给下一个中间件处理。
返回值是 HttpResponse 对象,Django 将不执行后续视图函数之前执行的方法以及视图函数,直接以该中间件为起点,倒序执行中间件,且执行的是视图函数之后执行的方法。
process_request 方法是在视图函数之前执行的。
当配置多个中间件时,会按照 MIDDLEWARE中 的注册顺序,也就是列表的索引值,顺序执行。
不同中间件之间传递的 request 参数都是同一个请求对象。
process_response 方法有两个参数,一个是 request,一个是 response,request 是请求对象,response 是视图函数返回的 HttpResponse 对象,该方法必须要有返回值,且必须是response。
process_response 方法是在视图函数之后执行的。
当配置多个中间件时,会按照 MIDDLEWARE 中的注册顺序,也就是列表的索引值,倒序执行
process_view 方法格式如下:
process_view(request, view_func, view_args, view_kwargs) process_view 方法有四个参数:
request 是 HttpRequest 对象。
view_func 是 Django 即将使用的视图函数。
view_args 是将传递给视图的位置参数的列表。
view_kwargs 是将传递给视图的关键字参数的字典。
view_args 和 view_kwargs 都不包含第一个视图参数(request)。
process_view 方法是在视图函数之前,process_request 方法之后执行的。
process_exception 方法如下:
process_exception(request, exception)
参数说明:
request 是 HttpRequest 对象。
exception 是视图函数异常产生的 Exception 对象。
process_exception 方法只有在视图函数中出现异常了才执行,按照 settings 的注册倒序执行。
在视图函数之后,在 process_response 方法之前执行。
process_exception 方法的返回值可以是一个 None 也可以是一个 HttpResponse 对象。
返回值是 None,页面会报 500 状态码错误,视图函数不会执行。
class MD1(MiddlewareMixin):
def process_request(self, request):
print("md1 process_request 方法。", id(request)) #在视图之前执行
def process_response(self,request, response): :#基于请求响应
print("md1 process_response 方法!", id(request)) #在视图之后
return response
def process_view(self,request, view_func, view_args, view_kwargs):
print("md1 process_view 方法!") #在视图之前执行 顺序执行
#return view_func(request)
def process_exception(self, request, exception):#引发错误 才会触发这个方法
print("md1 process_exception 方法!")
# return HttpResponse(exception) #返回错误信息
中间件应用场景
1、做IP访问频率限制
某些IP访问服务器的频率过高,进行拦截,比如限制每分钟不能超过20次。
2、URL访问过滤
如果用户访问的是login视图(放过)
如果访问其他视图,需要检测是不是有session认证,已经有了放行,没有返回login,这样就省得在多个视图函数上写装饰器了!
from django.utils.deprecation import MiddlewareMixin
from django .http import HttpResponse
white = ['127.0.0.1'] # 白名单
black = ['127.0.0.2'] # 黑名单
ban = {} # 小黑屋
ban_seconds = 3 # 三秒内
ban_limit = 5 # 三秒内允许访问5次
ban_time = 30 # 被封时间30秒
class AuthMD(MiddlewareMixin):
def process_request(self,request):
ip = str(request.META.get("REMOTE_ADDR"))
if ip in black:
return HttpResponse('禁止访问',status=403)
# 如果是第一次请求
if not ban.get(ip):
ban[ip] = {"total":1,"time":int(time.time()),"banTime":""}
print(ip,ban[ip].get("total"))
# 如果不是第一次请求 则判断上次请求和这次请求是否在合法时间内
if ban[ip]["time"] + ban_seconds > int(time.time()):
# 如果是三秒内 判断访问次数
if ban[ip]["total"] > ban_limit:
# 如果访问次数大于限制次数 直接return 将ip关小黑屋 设置限制时间
ban[ip]["banTime"] = int(time.time()) + ban_time
return self.ban_response()
# 如果没有大于限制次数
ban[ip]["total"] += 1
print(ban)
# 如果不是在合法时间内请求
else:
# 先根据此ip找封的时间
limit_time = ban[ip]["banTime"]
# 如果已经禁止,则过ban_seconds秒后才可以解除
if limit_time and limit_time > int(time.time()):
return self.ban_response()
# 过了限制时间,解除限制
del ban[ip]
def ban_response(self):
return HttpResponse(f"访问过于频繁,请{ban_time}秒后重试!")
def process_response(self,request,response):
return response
3.模板配置和模板语法
1.在django根目录下创建模板文件夹用来存放模板文件 (template)
2.settings.py中的TEMPLATES里的DIRS配置模板路径
3.使用模板,在文件夹下创建html文件
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<a href="#" >{{ name|cut:"" | lower |capfirst }}老师</a><br>
<a href="#" >性别:{{ gender }}</a><br>
<a href="#" >年龄:{{ age}}</a><br>
<a href="#" >num1 {{ num1|add:num2 }}</a><br>
<a href="#" >num2 {{ num2| add:num1}}</a><br>
</body>
</html>
在views中编写
def test4(request):
name1 = 'q dsfadgRERETD'
gender = '男'
age = 34
num1 = 1
num2 = 2
context = {
'name': name1,
'gender': gender,
'age': age,
'num1': num1,
'num2':num2
}
return render(request, 'index.html',context=context)
6总结
- 1.掌握类视图的使用
- 2.掌握类视图的使用场景
- 3.了解中间件的流程
- 掌握模板的设置和使用