前言
大家应该都遇到过,在某些页面中,我们不希望匿名用户能够访问,例如个人页面等,这种页面只允许已经登录的用户去访问,在django中,我们也有比较多的方式去实现。
最简单的,我们在viewz中去判断用户is_authenticated,但这种方法也相对比较笨拙,最理想的的我们当然不希望这个请求能够进入到我们view,在这之前就能够返回一个相关的response,而django其实已经给我们封装好了相关的函数与类。下面话不多说了,来一起看看详细的介绍吧。
基于fbv模式的login_required装饰器
1
2
3
4
|
def login_required(function = None , redirect_field_name = REDIRECT_FIELD_NAME, login_url = None ): # 实际上这个方法也是调用is_authenticated去判断 pass |
使用方法也很简单:
1
2
3
4
5
6
|
# fbv模式 from django.contrib.auth.decorators import login_required @login_required def user_info_view(request): # 用户个人界面 pass |
那么,我们希望如果是匿名用户在访问这个界面后能够重定向到login界面,我们可以设置相关参数,login_required装饰器会默认去读取settings.LOGIN_URL
,并重定向到这个页面,如果希望更为灵活,那么我们也可以给装饰器传相关参数。
1
2
3
4
5
|
# fbv模式 @login_required (login_url = '/login/' , redirect_field_name = 'next' ) def user_info_view(request): # 用户个人界面 pass |
login_url就是匿名用户访问后重定向的url,一般都是login的页面
redirect_field_name是一个get请求的参数
假设当前页面会/user/info/
那么重定向的url为: /login/?next=/user/info/
这个参数可以用于登陆后直接跳转回这个页面,后面还会具体介绍!
基于cbv的LoginRequiredMixin类
博主一般常用都是cbv模式,在这个模式下,我们会重写get和post方法,理论上可以用login_required装饰器去装饰这两个方法
1
2
3
4
5
6
7
8
|
# cbv模式 from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator class UserInfoView(View): @method_decorator (login_required(login_url = '/login/' , redirect_field_name = 'next' )) def get( self , request): # 获取用户个人界面 pass |
login_required是函数装饰器,method_decorator可以将函数装饰器转化成方法装饰器。如果这里还有post请求,那这样的代码我们还要在写一遍,这样就显得有点冗余,我们既然用了类来实现,当然通过类的优势来实现!继承LoginRequiredMixin!
1
2
3
4
5
|
from django.contrib.auth.mixins import LoginRequiredMixin class UserInfoView(LoginRequiredMixin, View): def get( self , request): # 获取用户个人界面 pass |
那么,LoginRequiredMixin是怎么去实现的呢?
看看源代码
1
2
3
4
5
|
class LoginRequiredMixin(AccessMixin): def dispatch( self , request, * args, * * kwargs): if not request.user.is_authenticated(): return self .handle_no_permission() return super (LoginRequiredMixin, self ).dispatch(request, * args, * * kwargs) |
其实它重写了dispatch方法,因为我们还继承了view,其实它重写的view中的dispatch函数,如果知道view的逻辑,你就知道为什么能够这样实现了!
当我们在url中,调用你的view类,如UserInfoView.as_view()
方法,它会去调用dispatch()
,这个方法起到一个分配器的作用,如果get请求,那么他就调用get方法,如果是post请求,那么就调用post方法。那么,在dispatch中去判断用户是否登录,当然可以起到这个作用。
那既然只是重写dispatch,我们也可以自己实现!
1
2
3
4
5
6
|
# 自定义LoginRequiredMixin class LoginRequiredMixin( object ): @method_decorator (login_required(login_url = '/login/' , redirect_field_name = 'next' )) def dispatch( self , request, * args, * * kwargs): return super (LoginRequiredMixin, self ).dispatch(request, * args, * * kwargs) |
当然,有没有必要自己实现,那就看各自的需求啦~
重定向与跳转
1
|
(login_url = '/login/' , redirect_field_name = 'next' ) |
这两个参数提供了一个重定向与跳转的url给我们,当匿名用户登录需要登录的页面时,就会跳转到login_url,这个get请求还带着redirect_field_name参数,值是'next'。
假如他访问的是个人页面,那么跳转到
http://127.0.0.1/login/?next=/user/info/
我们可以通过这个参数,在登录后直接跳转到个人页面。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
class LoginView(View): """ 用户登录逻辑 """ def get( self , request): # 获取到next参数,渲染到template中,在form表单添加一个hidden类型的元素 next = request.GET.get( 'next' , '') return render(request, "login.html" , { 'next' : next }) def post( self , request): login_form = LoginForm(request.POST) if login_form.is_valid(): user_name = request.POST.get( "username" , "") pass_word = request.POST.get( "password" , "") next = request.POST.get( 'next' , '') user = authenticate(username = user_name, password = pass_word) if user is not None : if user.is_active: login(request, user) if next : # 如果next存在,直接跳转到指定页面 return HttpResponseRedirect( next ) # 不存在跳转到index界面 return HttpResponseRedirect(reverse( 'index' )) else : return render(request, "login.html" , { "msg" : "用户未激活" }) else : return render(request, "login.html" , { "msg" : "用户名或密码错误" }) else : return render(request, "login.html" , { "login_form" : login_form}) |
1
2
|
# login.html template form中添加 < input name = "next" type = "hidden" value = "{{ next }}" / > |
普通页面的登录跳转问题
如果普通页面也想要实现登录后跳转回原来的页面,十分简单,在request中有个path参数,它表示当前页面,我们只需要在跳转到login界面把这个参数带上即可
1
2
3
4
|
# template < a class = "loginbtn" href = "/login/?next={{ request.path }}" rel = "external nofollow" >登录</ a > < a class = 'logoutbtn' href = "/logout/?next={{ request.path }}" rel = "external nofollow" 退出</a> < a class = 'registerbtn' href = "/register/?next={{ request.path }}" rel = "external nofollow" 注册</a> |
login的实现逻辑同上面的一样,其实logout和注册界面的实现逻辑也是一样的。
1
2
3
4
5
6
7
8
9
|
# logout class LogoutView(View): def get( self , request): next = request.GET.get( 'next' , '') logout(request) try : return HttpResponseRedirect( next ) except : return HttpResponseRedirect(reverse( 'index' )) |
后言
本篇重点在于@login_required装饰器的使用,以及LoginReqiredMixin类的使用和自定义,最后实现登录的重定向以及跳转!
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://juejin.im/post/5a780ced6fb9a063395c4b6f