Django寫一個裝飾器:從首頁點選詳情頁,如已登入,進詳情頁;如未登入,跳轉至登入頁面,登入成功後,跳轉至詳情頁
有的網站需求,如果使用者未登入,能夠進入首頁,但當點選想要進入詳情頁的時候,就會跳轉到登入頁面,登入完成之後,有的需求需要進入首頁;有的需要進入點選登入之前你的意向頁面
第一種:登入之後,進入首頁。
第二種:登入之後,進入登入之前你點選想進入的意向頁面
那麼,對於第一種,登入之後,進入首頁。Django有一種自帶裝飾器。比較簡單,下面講解:
在views.py中:
一、如果是普通檢視函式:則使用login_required
from django.contrib.auth.views import login_required @login_required def add(request): if request.method == 'GET': return render(request, './subject/add.html') elif request.method == 'POST': try: name = request.POST.get('name') amount = request.POST.get('amount') days = request.POST.get('days') number = request.POST.get('number') assurance = request.POST.get('assurance') remark = request.POST.get('remark') s = SubjectModel(name=name,amount=amount,days=days,number=number,assurance = assurance,remark=remark,creater_id=request.user.id,updater_id=request.user.id) s.save() return redirect('/subject/list') except: return render(request,'./subject/add.html',{'result':'學科新增失敗!請仔細檢查'})
二、如果是通用檢視函式,使用method_decorator
from django.utils.decorators import method_decorator class SubjectAddView(View): """ 該通用檢視是用來展示新增學科的頁面subject/add.html,以及處理學科的新增邏輯。 """ @method_decorator(login_required) def get(self, request): return render(request, 'subject/add.html') @method_decorator(login_required) def post(self, request): subject = Subject() subject.name = request.POST.get('name') subject.amount = request.POST.get('amount') subject.days = request.POST.get('days') subject.number = request.POST.get('number') # 儲存學科之前,先判斷學科是否已經存在。 result = Subject.objects.filter(name=subject.name) if result: error = {'code': '該學科已存在!'} # 資料庫已經存在該名稱的學科 return render(request, 'subject/add.html', locals()) # 儲存成功,切換Url,進入/subject/index/首頁,展示所新增的學科資訊。 # 給學科新增建立人和更新人對應的使用者。預設都是當前登入使用者。 subject.creater = request.user subject.updater = request.user subject.save() return redirect(reverse('subject_index'))
上面是通用檢視函式和普通檢視函式的使用裝飾器不同,但是有一點,必須要在settings.py中設定:
新增下面一句話:就是制定被裝飾函式,如果沒使用者登入,所要跳轉的網址。在這裡就是跳轉到登入頁面
LOGIN_URL = '/user/login/'
下面,講解第二種,登入之後,進入登入之前你點選想進入的意向頁面
這個都需要進行自定義裝飾器了,因為在使用者沒登入的情況下,你要點選首頁上的某一個連結進入詳情頁。要點選的連結都不一樣,也就是意向頁面不一樣。登入之後,要去意向頁面。
思路:在首頁的時候,你點選某一個連結,想要進入詳情頁。一、如果使用者已登入,直接進入意向頁面。二、1.如果沒有使用者登入,需要自動跳轉至登入頁面 2.在跳轉至登入頁面之前,需要將使用者所點選的意向頁面url地址,儲存在cookie中記錄下來 3.跳轉至登入頁面之後,如果使用者登入成功,那麼就會從cookie取出,在第2步儲存到cookie中的意向url地址,進行重定向即可。
在detail的函式中:
def detail(request,article_id):
article = Article.objects.get(id=article_id)
comment_form = CommentForm()
comments = article.comment_set.all()
return render(request,'article_page.html',locals())
在登入login的函式中:
def login_func(request):
if request.method == 'GET':
return render(request,'login.html')
elif request.method == 'POST':
login_form = LoginForm(request.POST)
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
user= NewUser.objects.filter(uname=username,upwd=password)
if user:
# 允許登入,儲存登入的session資訊
request.session['uname'] = username
# 重定向:需要區分使用者直接點選的登入頁面進行的登入,還是由其他的頁面跳轉過來的。
# 如果使用者直接訪問的是登入頁面,那麼直接跳轉到首頁。
# 如果是從其他頁面跳轉過來的,需要獲取使用者所點選的url地址。比如:使用者點選文章標題之後跳轉的;使用者點選評論之後跳轉的;登入之後直接重定向到使用者點選的url地址。
user_click_url = request.COOKIES.get('click_url','')
if not user_click_url:
# 說明是使用者直接訪問的就是登入頁面
return redirect(reverse('blog_index'))
else:
# 說明是點選其他連結,跳轉過來的。
return redirect(user_click_url)
else:
return render(request,'login.html',{'error':'使用者名稱和密碼錯誤'})
下面,寫裝飾器:
from django.http import HttpResponseRedirect
def islogin(func_name):
def wrapper(request,*args,**kwargs):
if request.session.get('uname',''):
# 說明當前處於登入狀態,直接呼叫func_name即可
return func_name(request,*args,**kwargs)
else:
# 此時需要獲取使用者所點選的url,並儲存到cookie當中,再跳轉到登入頁面。
response = HttpResponseRedirect('/blog/login/')
# 使用者點選連結,會發送GET請求,對應的request物件中,含有要請求的url地址、請求引數,等等
response.set_cookie('click_url',request.path)
return response
return wrapper
之後,只需要在detail的函式的上面,加上封裝好的裝飾器即可。
當跳轉至登入頁面的時候,會看到瀏覽器中cookie會有儲存的click_url的欄位
其中,有兩個小知識點:
一、進行重定向的時候,
如果url路徑中有引數,r’^detail/(?P<article_id>\d+)/$’,如何使用reverse()來反射這個帶引數的地址?
下面是解決方案:
return redirect(reverse('blog_detail',args=(article_id,)))
如果url路徑中沒有引數,但是含有?article_id=1這種請求的引數,如何使用reverse()來反射這個url
下面是解決方案
return redirect(reverse('article'+'?article_id='+article_id))
二、裝飾器中使用request.path
使用者點選連結,會發送GET請求,對應的request物件中,含有要請求的url地址、請求引數,等等
一、如果url路徑中有引數:例如localhost:8000/blog/detail/1/
是在request.path中可以獲取,傳送請求的網址
二、如果url路徑中沒有引數,但是含有?article_id=1這種請求的引數。例如:localhost:8000/blog/?article_id=1/ 是在request.get_full_path()中可以獲取,傳送請求的網址。要不然,使用request.path只會獲取到?之前的網站,獲取不是完整的