您好,登錄后才能下訂單哦!
前言
大家應(yīng)該都遇到過,在某些頁面中,我們不希望匿名用戶能夠訪問,例如個(gè)人頁面等,這種頁面只允許已經(jīng)登錄的用戶去訪問,在django中,我們也有比較多的方式去實(shí)現(xiàn)。
最簡(jiǎn)單的,我們?cè)趘iewz中去判斷用戶is_authenticated,但這種方法也相對(duì)比較笨拙,最理想的的我們當(dāng)然不希望這個(gè)請(qǐng)求能夠進(jìn)入到我們view,在這之前就能夠返回一個(gè)相關(guān)的response,而django其實(shí)已經(jīng)給我們封裝好了相關(guān)的函數(shù)與類。下面話不多說了,來一起看看詳細(xì)的介紹吧。
基于fbv模式的login_required裝飾器
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None): # 實(shí)際上這個(gè)方法也是調(diào)用is_authenticated去判斷 pass
使用方法也很簡(jiǎn)單:
# fbv模式 from django.contrib.auth.decorators import login_required @login_required def user_info_view(request): # 用戶個(gè)人界面 pass
那么,我們希望如果是匿名用戶在訪問這個(gè)界面后能夠重定向到login界面,我們可以設(shè)置相關(guān)參數(shù),login_required裝飾器會(huì)默認(rèn)去讀取settings.LOGIN_URL
,并重定向到這個(gè)頁面,如果希望更為靈活,那么我們也可以給裝飾器傳相關(guān)參數(shù)。
# fbv模式 @login_required(login_url='/login/', redirect_field_name='next') def user_info_view(request): # 用戶個(gè)人界面 pass
login_url就是匿名用戶訪問后重定向的url,一般都是login的頁面
redirect_field_name是一個(gè)get請(qǐng)求的參數(shù)
假設(shè)當(dāng)前頁面會(huì)/user/info/
那么重定向的url為: /login/?next=/user/info/
這個(gè)參數(shù)可以用于登陸后直接跳轉(zhuǎn)回這個(gè)頁面,后面還會(huì)具體介紹!
基于cbv的LoginRequiredMixin類
博主一般常用都是cbv模式,在這個(gè)模式下,我們會(huì)重寫get和post方法,理論上可以用login_required裝飾器去裝飾這兩個(gè)方法
# 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): # 獲取用戶個(gè)人界面 pass
login_required是函數(shù)裝飾器,method_decorator可以將函數(shù)裝飾器轉(zhuǎn)化成方法裝飾器。如果這里還有post請(qǐng)求,那這樣的代碼我們還要在寫一遍,這樣就顯得有點(diǎn)冗余,我們既然用了類來實(shí)現(xiàn),當(dāng)然通過類的優(yōu)勢(shì)來實(shí)現(xiàn)!繼承LoginRequiredMixin!
from django.contrib.auth.mixins import LoginRequiredMixin class UserInfoView(LoginRequiredMixin, View): def get(self, request): # 獲取用戶個(gè)人界面 pass
那么,LoginRequiredMixin是怎么去實(shí)現(xiàn)的呢?
看看源代碼
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)
其實(shí)它重寫了dispatch方法,因?yàn)槲覀冞€繼承了view,其實(shí)它重寫的view中的dispatch函數(shù),如果知道view的邏輯,你就知道為什么能夠這樣實(shí)現(xiàn)了!
當(dāng)我們?cè)趗rl中,調(diào)用你的view類,如UserInfoView.as_view()
方法,它會(huì)去調(diào)用dispatch()
,這個(gè)方法起到一個(gè)分配器的作用,如果get請(qǐng)求,那么他就調(diào)用get方法,如果是post請(qǐng)求,那么就調(diào)用post方法。那么,在dispatch中去判斷用戶是否登錄,當(dāng)然可以起到這個(gè)作用。
那既然只是重寫dispatch,我們也可以自己實(shí)現(xiàn)!
# 自定義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)
當(dāng)然,有沒有必要自己實(shí)現(xiàn),那就看各自的需求啦~
重定向與跳轉(zhuǎn)
(login_url='/login/', redirect_field_name='next')
這兩個(gè)參數(shù)提供了一個(gè)重定向與跳轉(zhuǎn)的url給我們,當(dāng)匿名用戶登錄需要登錄的頁面時(shí),就會(huì)跳轉(zhuǎn)到login_url,這個(gè)get請(qǐng)求還帶著redirect_field_name參數(shù),值是'next'。
假如他訪問的是個(gè)人頁面,那么跳轉(zhuǎn)到
http://127.0.0.1/login/?next=/user/info/
我們可以通過這個(gè)參數(shù),在登錄后直接跳轉(zhuǎn)到個(gè)人頁面。
class LoginView(View): """ 用戶登錄邏輯 """ def get(self, request): # 獲取到next參數(shù),渲染到template中,在form表單添加一個(gè)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存在,直接跳轉(zhuǎn)到指定頁面 return HttpResponseRedirect(next) # 不存在跳轉(zhuǎn)到index界面 return HttpResponseRedirect(reverse('index')) else: return render(request, "login.html", {"msg": "用戶未激活"}) else: return render(request, "login.html", {"msg": "用戶名或密碼錯(cuò)誤"}) else: return render(request, "login.html", {"login_form": login_form})
# login.html template form中添加 <input name="next" type="hidden" value="{{ next }}"/>
普通頁面的登錄跳轉(zhuǎn)問題
如果普通頁面也想要實(shí)現(xiàn)登錄后跳轉(zhuǎn)回原來的頁面,十分簡(jiǎn)單,在request中有個(gè)path參數(shù),它表示當(dāng)前頁面,我們只需要在跳轉(zhuǎn)到login界面把這個(gè)參數(shù)帶上即可
# 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" 注冊(cè)</a>
login的實(shí)現(xiàn)邏輯同上面的一樣,其實(shí)logout和注冊(cè)界面的實(shí)現(xiàn)邏輯也是一樣的。
# logout class LogoutView(View): def get(self, request): next = request.GET.get('next', '') logout(request) try: return HttpResponseRedirect(next) except: return HttpResponseRedirect(reverse('index'))
后言
本篇重點(diǎn)在于@login_required裝飾器的使用,以及LoginReqiredMixin類的使用和自定義,最后實(shí)現(xiàn)登錄的重定向以及跳轉(zhuǎn)!
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。