1. 程式人生 > >Django寫一個裝飾器:從首頁點選詳情頁,如已登入,進詳情頁;如未登入,跳轉至登入頁面,登入成功後,跳轉至詳情頁

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只會獲取到?之前的網站,獲取不是完整的