simple_tag,filte,分頁以及cookie和裝飾器

自定義simple_tag

內置的方法

首先Django中包含了很多內置的方法:


這裏通過lower實現


在views視圖函數中寫如下代碼:

def tp3(request):
    name= "ABCDEFG"
    return  render(request,"tp3.html",{"name":name})

在urls路由關係中添加如下:

url(r'^tp3/',views.tp3),

在tp3頁面中寫如下:

    {{ name }}
    {{ name|lower }}

最後效果如下:

997599-20170105165110753-1856827620.png

自定義方法

使用simple_tag的方法:


1、    在app下創建templatetags目錄

2、    創建py文件

3、    創建template對象register

4、    @register.simple_tag

        def func()

        如果函數有參數:def func(a1,a2)

5、    在settings配置文件註冊app

6、    在頁面文件頂部{%load py文件%},如果存在繼承,這個要放在繼承下面

7、    最後在頁面使用的時候{% func %},如果有參數

        {%func 2 3 %}

這裏有幾個問題需要注意:

1、    在app下創建templatetags目錄必須爲templatetags不能更改

2、    創建py文件的時候名字可以隨便定義

3、    在py文件中必須寫如下代碼:

from django import template
from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag

這四行代碼必須有,並且的template對象register名字不能更改

按照上面的規則,在app下創建templatetags目錄

然後創建一個test.py文件,代碼如下:

#AUTHOR:FAN
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag
def func():
    return 123

並在setting中添加:

997599-20170105165243034-1721204570.png


tp3.html中代碼如下(注意高亮部分):

{% load test %}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ name }}
    {{ name|lower }}
    {% func %}
</body>
</html>

最後效果如下:


997599-20170105165324691-837106578.png


我們將test中的func改成傳遞參數的,如下所示:

def func(a1,a2):
    return a1+a2

在tp3.html中傳遞參數:

  {% func 5 3 %}

結果如下:

997599-20170105165344456-459838540.png


自定義filter

filter和simple_tag的方法基本一樣,只需要做如下修改:


將test.py文件中@register.simple_tag替換爲@register.filter


在頁面中代碼改爲:

{{ "zhaofan" |func:"趙凡" }}

這樣最終在頁面的效果如下:

997599-20170105165417003-854005653.png

而這裏對比filter和simple_tag,我們可以發現各有優缺點


1、其中fileter可以放在模板語言中的if條件中,而simple_tag則不能如

    {% if "zhaofan" |func:"趙凡" %}
    {% endif %}


2、filter參數固定,simple_tag參數任意



分頁


在前端防止因爲xss而現實字符串的可以通{{ page_str|save}}


後端:可以通過導入from django.utils.safestring import mark_safe,然後page_str = mark_safe(page_str)


通過下面例子用於理解分頁


這裏將分頁的功能封裝了一個類,改類內容如下:

#AUTHOR:FAN
from django.utils.safestring import mark_safe
class Page:
    def __init__(self,current_page,data_count,per_page_count=10,page_num = 7):
        '''
        :param current_page: 當前頁
        :param data_count: 數據的總數目
        :param per_page_count: 每頁顯示的數目
        :param page_num: 顯示幾頁內容
        '''
        self.current_page = current_page
        self.data_count = data_count
        self.per_page_count=per_page_count
        self.page_num = page_num
    @property
    def start(self):
        '''
        :return: 返回得到起始
        '''
        return (self.current_page-1)*self.per_page_count
    @property
    def end(self):
        '''
        :return: 返回結束
        '''
        return self.current_page*self.per_page_count
    @property
    def total_count(self):
        '''
        :return: 返回總頁數
        '''
        v, y = divmod(self.data_count, self.per_page_count)
        if y:
            v += 1
        return v
    def page_str(self,base_url):
        '''
        :param base_url: 這裏是用於自定義url前綴
        :return: 返回的爲頁面下端要顯示的跳轉頁的html語言的字符串
        '''
        page_list = []
        if self.total_count < self.page_num:
            start_index = 1
            end_index = self.total_count + 1
        else:
            if self.current_page <= (self.page_num + 1) / 2:
                start_index = 1
                end_index = self.page_num + 1
            else:
                start_index = self.current_page - (self.page_num - 1) / 2
                end_index = self.current_page + (self.page_num + 1) / 2
                if self.current_page + (self.page_num + 1) / 2 > self.total_count:
                    end_index = self.total_count + 1
                    start_index = self.total_count - self.page_num + 1
        if self.current_page == 1:
            prev = '<a href="#">上一頁</a>'
        else:
            prev = '<a href="%s?p=%s">上一頁</a>' % (base_url,self.current_page - 1)
        page_list.append(prev)
        for i in range(int(start_index), int(end_index)):
            if i == self.current_page:
                temp = '<a class="page active" href="%s?p=%s">%s</a>' % (base_url,i, i)
            else:
                temp = '<a href="%s?p=%s">%s</a>' % (base_url,i, i)
            page_list.append(temp)
        if self.current_page == self.total_count:
            nex = '<a href="#">下一頁</a>'
        else:
            nex = '<a href="%s?p=%s">下一頁</a>' % (base_url,self.current_page + 1)
        page_list.append(nex)
        go_page = """
        <input type='text' /><a onclick="jumpTo(this,'%s?p=');">跳轉</a>
        <script>
            function jumpTo(ths,base){
                var val = ths.previousSibling.value;
                location.href = base + val;
            }
        </script>
        """ %(base_url)
        page_list.append(go_page)
        page_str = "".join(page_list)
        page_str = mark_safe(page_str)
        return page_str

在views函數中調用:

from utils import pagination
def user_list(request):
    current_page = request.GET.get("p",1)
    current_page = int(current_page)
    page_obj = pagination.Page(current_page,len(LI))
    data = LI[page_obj.start:page_obj.end]
    page_str = page_obj.page_str("/user_list/")
    return render(request,"user_list.html",{"data":data,"page_str":page_str})

最終的效果如下:

997599-20170105165539472-1343958241.png



cookie

客戶端瀏覽器上的一個文件


以字典的方式存在


通常很多網站登錄之後,網站的右上角會顯示當前用戶的用戶名,實現例子如下:


views裏寫如下代碼:

def login(request):
    print(request.method)
    if request.method=="GET":
        return render(request,"login.html")
    if request.method =="POST":
        u = request.POST.get("username")
        p = request.POST.get("pwd")
        dic = user_info.get(u)
        print(u,p)
        if not dic:
            return render(request,"login.html")
        if dic["pwd"] == p:
            res = redirect("/index")
            res.set_cookie('username1',u)
            return res
        else:
            return render(request, "login.html")
def index(request):
    #獲取當前登錄的用戶名
    v = request.COOKIES.get("username1")
    if not v:
        return redirect("/login")
    return render(request,"index.html",{"current_user":v})

這樣用戶如果沒有登錄的情況下就不能直接訪問index頁面了,並且如果用戶登錄之後也能顯示當前用戶的用戶名,也就是實現了用戶認證


設置Cookie:


res.set_cookie(key,value)


參數:

key              鍵

value=‘’       值

max_age=None      超時時間,以秒作爲單位。默認是關閉瀏覽器失效

expires=None      超時時間,這個是可以設置datatime

path="/"          Cookie生效的路徑

domain=None      Cookie生效的域名

secure=False      https傳輸

httponly=False    只能http協議傳輸,無法被JavaScript獲取


分頁改造(結合cookie)

user_list.html代碼如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .pagination .page{
            display: inline-block;
            padding: 5px;
            background-color: cyan;
            margin: 5px;
        }
        .pagination  .active{
            background-color: blue;
            color: white;
        }
    </style>
</head>
<body>
<ul>
    {% for item in data %}
        {% include 'li.html' %}
    {% endfor %}
</ul>
<div>
    <select id="ps" onchange="changePageSize(this)">
    <option value="10">10</option>
    <option value="20">20</option>
    <option value="30">30</option>
    <option value="40">40</option>
    </select>
</div>
<div  class="pagination">
{{ page_str }}
</div>
<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
    $(function () {
       var v  = $.cookie("per_page_count");
        $("#ps").val(v);
    });
    function  changePageSize(ths) {
        var v = $(ths).val();
        console.log(v);
        $.cookie("per_page_count",v);
        location.reload()
    }
</script>
</body>
</html>

997599-20170105165721987-975030049.png



頁面效果如上,實現的功能是當通過下拉框選擇不同的選項時,即每頁顯示的數量,這裏利用了jquery的cookie,jquery.cookie.js


關於cookie的加密

前文中我們通過

res.set_cookie('username1',u)

設置cookie,其實還有一種加密的方式,即:

res.set_signed_cookie("username1",u,salt="jiami")

通過salt這個參數實現加密,同樣的獲取cookie的時候也需要加上salt參數才能進行解密


用戶認證裝飾器

FBV的裝飾器用法

我們前面代碼中:

def index(request):
    #獲取當前登錄的用戶名
    v = request.COOKIES.get("username1")
    if not v:
        return redirect("/login")
    return render(request,"index.html",{"current_user":v})

如果我們有多頁面都需要判斷用戶是否登錄,如果每個都這樣寫就需要寫很多遍,所以這裏我們可以通過裝飾器實現

將上述代碼進行更改:

def auth(func):
    def inner(request,*args,**kwargs):
        v = request.COOKIES.get("username1")
        if not v:
            return redirect("/login")
        return func(request,*args,**kwargs)
    return inner
@auth
def index(request):
    #獲取當前登錄的用戶名
    v = request.COOKIES.get("username1")
    return render(request,"index.html",{"current_user":v})

CBV的裝飾器用法

下面是一個普通的CBV用法例子:

from django import views
class Order(views.View):
    def get(self,request):
        v = request.COOKIES.get("username1")
        if not v:
            return redirect("/login")
        return render(request, "index.html", {"current_user": v})
    def post(self,request):
        v = request.COOKIES.get("username1")
        return render(request, "index.html", {"current_user": v})

如果我們只對get請求做認證

def auth(func):
    def inner(request,*args,**kwargs):
        v = request.COOKIES.get("username1")
        if not v:
            return redirect("/login")
        return func(request,*args,**kwargs)
    return inner
from django import views
from django.utils.decorators import method_decorator
class Order(views.View):
    @method_decorator(auth)
    def get(self,request):
        v = request.COOKIES.get("username1")
        return render(request, "index.html", {"current_user": v})
    
    def post(self,request):
        v = request.COOKIES.get("username1")
        return render(request, "index.html", {"current_user": v})

這樣當訪問order的時候就加上了驗證功能


但是這樣是隻給get方法加驗證,如果想要給更多得方法加驗證的時候,通過下面方法實現:

def auth(func):
    def inner(request,*args,**kwargs):
        v = request.COOKIES.get("username1")
        if not v:
            return redirect("/login")
        return func(request,*args,**kwargs)
    return inner
from django import views
from django.utils.decorators import method_decorator
class Order(views.View):
    @method_decorator(auth)
    def dispatch(self, request, *args, **kwargs):
        return super(Order,self).dispatch(request, *args, **kwargs)
    def get(self,request):
        v = request.COOKIES.get("username1")
        return render(request, "index.html", {"current_user": v})
    def post(self,request):
        v = request.COOKIES.get("username1")
        return render(request, "index.html", {"current_user": v})

因爲CBV每次需要先執行一個dispatch方法,我們在dispatch方法上加認證,這樣就相當於在所有的上面加上了認證


但是這種方法有人會覺得多寫了一個dispatch方法,可以將其簡化爲:

@method_decorator(auth,name="dispatch")
class Order(views.View):
    def get(self,request):
        v = request.COOKIES.get("username1")
        return render(request, "index.html", {"current_user": v})
    def post(self,request):
        v = request.COOKIES.get("username1")
        return render(request, "index.html", {"current_user": v})


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章