关于method_decorator的作用,以及不再使用method_decorator为装饰器,添加self
1.method_decorator的作用:
为函数视图装饰器补充第一个参数self,以适配类视图的方法;
如果装饰器本身就可以适配类视图的方法,就无须再使用method_decorator
def my_decorator(view_func):
def wrapper(request,*args,**kwargs):
print('装饰器被调用')
print(request.path)
return view_func(request,*args,**kwargs)
return wrapper
#method_decorator装饰器为函数视图装饰器(就是wrapper)补充第一个self参数,以适配类视图方法
@method_decortaor(my_decorator,name='disatch')
class DemoView(View):
def get(self,request):
return HttpResponse('aaa')
def post(self,request):
return HttpResponse('bbb')
我们可以自己补充self,就不再使用method_decorator
def my_decorator(view_func):
def wrapper(self,request,*args,**kwargs):
print('装饰器被调用')
print(request.path)
return view_func(self,request,*args,**kwargs)
return wrapper
@my_decorator
class DemoView(View):
def get(self,request):
return HttpResponse('aaa')
def post(self,request):
return HttpResponse('bbb')
def check_ip(func):
#实现禁止ip黑名单访问发帖界面.可以通过在视图函数使用装饰器实现
def wrapper(request,*args,**kwargs):
#禁止ip黑名单访问
IP = request.META.get('REMOTE_ADDR')
if IP in ['192.168.168.11']:
return HttpResponse("此IP禁止访问")
return func(request,*args,**kwargs)
return wrapper
补充一个login_required -- 登录验证装饰器:
源码:
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
"""
Decorator for views that checks that the user is logged in, redirecting
to the log-in page if necessary.
"""
actual_decorator = user_passes_test(
lambda u: u.is_authenticated,
login_url=login_url,
redirect_field_name=redirect_field_name
)
if function:
return actual_decorator(function)
return actual_decorator
# user_passes_test源码
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
Decorator for views that checks that the user passes the given test,
redirecting to the log-in page if necessary. The test should be a callable
that takes the user object and returns True if the user passes.
"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
path = request.build_absolute_uri()
resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
current_scheme, current_netloc = urlparse(path)[:2]
if ((not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)):
path = request.get_full_path()
from django.contrib.auth.views import redirect_to_login
return redirect_to_login(
path, resolved_login_url, redirect_field_name)
return _wrapped_view
return decorator
#1.直接在类的视图中写登录校验实现:
"""
Django用户认证系统提供了request.user.is-authenticated()来判断用户是否登录,如果登录返回True,反之,返回False;
缺点:登录认证逻辑需要地方太多,代码重复多次
"""
class UserInfoView(View):
'''用户中心'''
def get(self,request):
'''个人信息界面'''
if request.user.is_authenticated():
return render(request,'user_center_info.html')
else:
return redirect(reverse('users:login'))
#2.1(URLconf装饰使用方法)对路由中的as_view()使用装饰器:login_required
'''在定义路由时添加:'''
url(r'^info/$',login_required(views.UserinfoView.as_view()),name='info')
#2.2装饰基于函数的视图
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
@login_required
def my_view(request):
if request.method == 'GET':
return HttpResponse('result')
#2.3装饰类的视图
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TempalteView):
template_name = 'secret.html'
@method_decorator(login_required)
def dispatch(self,*args,**kwargs):
return super(ProtectedView,self).dispatch(*args,**kwargs)
# 2.4 装饰通过Mixin类继承来实现:
from django.contrib.auth.decorators import login-required
from django.http import HttpResponse
from django.shortcuts import render
from django.views.generic import View
from .forms import MyForm
class LoginRequiredMixin(object):
@classmethod
def as_view(cls,**kwargs):
view == super(LoginRequiredMixin,cls).as_view(**initkwargs)
return login_required(view)
class MyFormView(LoginRequiredMixin,View):
form_class = MyForm
initial = {'key':'value'}
template_name = 'form_template.html'
def get(self,request,*args,**kwargs):
form = self.form_class(initial = self.initial)
return render(request,self.template_name,{'form':form})
#3.定义验证用户是否登录扩展类
'''使用Django自带的login_required装饰器来完成扩展,完成扩展后需要该功能的视图只需多继承该类就可以,复用率很高'''
#自定义的工具目录:
from django.contrib.auth.decorator import login_required
class LoginRequiredMinxin(object):
@classmethod
def as_view(cls,**kwargs):
view = super().as_view(**kwargs)
return login_required(view)
#使用时导包,并同时继承自定义类LoginRequiredMixin和View即可:
class UserInfoView(LoginRequiredMixin,View):
'''用户中心'''
def get(self,request):
'''个人信息页面'''
return render(request,'user_center_info.html')
'''
3.1装饰器login_required会自带next参数,和重定向地址,用于登陆后跳转以及不满足登录状态的重定向地址;
3.2 如果未设置登录验证则被重定向到LOGIN_URL配置(settings.py)项指定的地址;
3.3 在设置文件添加如下配置:表示当前用户未通过登录验证时,将用户重定向到/login/登录页面,LOGIN_URL = '/login/'
3.4 若不设置,默认未通过的登录验证时跳转路径是:/account/login/
3.5 跳转后的next参数,帮助用户完成登录后,自动跳转回登录前的页面
'''