自定義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 }}
最後效果如下:
自定義方法
使用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中添加:
tp3.html中代碼如下(注意高亮部分):
{% load test %} <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ name }} {{ name|lower }} {% func %} </body> </html>
最後效果如下:
我們將test中的func改成傳遞參數的,如下所示:
def func(a1,a2): return a1+a2
在tp3.html中傳遞參數:
{% func 5 3 %}
結果如下:
自定義filter
filter和simple_tag的方法基本一樣,只需要做如下修改:
將test.py文件中@register.simple_tag替換爲@register.filter
在頁面中代碼改爲:
{{ "zhaofan" |func:"趙凡" }}
這樣最終在頁面的效果如下:
而這裏對比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})
最終的效果如下:
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>
頁面效果如上,實現的功能是當通過下拉框選擇不同的選項時,即每頁顯示的數量,這裏利用了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})