【python】-- Django 分頁 、cookie、Session、CSRF

Django  分頁 、cookie、Session、CSRF

1、分頁

分頁功能在每一個網站都是必要的,下面主要介紹兩種分頁方式:javascript

一、Django內置分頁html

from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

L = []
for i in range(999):
    L.append(i)

def index(request):
    current_page = request.GET.get('p')

    paginator = Paginator(L, 10)
    # per_page: 每頁顯示條目數量
    # count:    數據總個數
    # num_pages:總頁數
    # page_range:總頁數的索引範圍,如: (1,10),(1,200)
    # page:     page對象
    try:
        posts = paginator.page(current_page)
        # has_next              是否有下一頁
        # next_page_number      下一頁頁碼
        # has_previous          是否有上一頁
        # previous_page_number  上一頁頁碼
        # object_list           分頁以後的數據列表
        # number                當前頁
        # paginator             paginator對象
    except PageNotAnInteger:
        posts = paginator.page(1)
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)
    return render(request, 'index.html', {'posts': posts})
views.py
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<ul>
    {% for item in posts %}
        <li>{{ item }}</li>
    {% endfor %}
</ul>

<div class="pagination">
      <span class="step-links">
        {% if posts.has_previous %}
            <a href="?p={{ posts.previous_page_number }}">Previous</a>
        {% endif %}
          <span class="current">
            Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
          </span>
          {% if posts.has_next %}
              <a href="?p={{ posts.next_page_number }}">Next</a>
          {% endif %}
      </span>

</div>
</body>
</html>
HTML
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger


class CustomPaginator(Paginator):
    def __init__(self, current_page, max_pager_num, *args, **kwargs):
        """
        :param current_page: 當前頁
        :param max_pager_num:最多顯示的頁碼個數
        :param args:
        :param kwargs:
        :return:
        """
        self.current_page = int(current_page)
        self.max_pager_num = max_pager_num
        super(CustomPaginator, self).__init__(*args, **kwargs)

    def page_num_range(self):
        # 當前頁面
        # self.current_page
        # 總頁數
        # self.num_pages
        # 最多顯示的頁碼個數
        # self.max_pager_num
        print(1)
        if self.num_pages < self.max_pager_num:
            return range(1, self.num_pages + 1)
        print(2)
        part = int(self.max_pager_num / 2)
        if self.current_page - part < 1:
            return range(1, self.max_pager_num + 1)
        print(3)
        if self.current_page + part > self.num_pages:
            return range(self.num_pages + 1 - self.max_pager_num, self.num_pages + 1)
        print(4)
        return range(self.current_page - part, self.current_page + part + 1)


L = []
for i in range(999):
    L.append(i)

def index(request):
    current_page = request.GET.get('p')
    paginator = CustomPaginator(current_page, 11, L, 10)
    # per_page: 每頁顯示條目數量
    # count:    數據總個數
    # num_pages:總頁數
    # page_range:總頁數的索引範圍,如: (1,10),(1,200)
    # page:     page對象
    try:
        posts = paginator.page(current_page)
        # has_next              是否有下一頁
        # next_page_number      下一頁頁碼
        # has_previous          是否有上一頁
        # previous_page_number  上一頁頁碼
        # object_list           分頁以後的數據列表
        # number                當前頁
        # paginator             paginator對象
    except PageNotAnInteger:
        posts = paginator.page(1)
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)

    return render(request, 'index.html', {'posts': posts})
擴展內置分頁:views.py
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<ul>
    {% for item in posts %}
        <li>{{ item }}</li>
    {% endfor %}
</ul>

<div class="pagination">
<span class="step-links">
{% if posts.has_previous %}
    <a href="?p={{ posts.previous_page_number }}">Previous</a>
{% endif %}

    {% for i in posts.paginator.page_num_range %}
        <a href="?p={{ i }}">{{ i }}</a>
    {% endfor %}

    {% if posts.has_next %}
        <a href="?p={{ posts.next_page_number }}">Next</a>
    {% endif %}
</span>

<span class="current">
Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
</span>

</div>
</body>
</html>
擴展內置分頁:Html

二、自定義分頁前端

需求:java

一、設定每頁顯示數據條數python

二、用戶輸入頁碼(第一頁、第二頁...)jquery

三、設定顯示多少頁號ajax

四、獲取當前數據總條數sql

五、根據設定顯示多少頁號和數據總條數計算出,總頁數數據庫

六、根據設定的每頁顯示條數和當前頁碼,計算出須要取數據表的起始位置django

七、在數據表中根據起始位置取值,頁面上輸出數據

八、輸出分頁html,如:[上一頁][1][2][3][4][5][下一頁]

2.一、templates下的模板:

<li>{{ item }}</li>
li.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .pagination .page{
            display: inline-block;
            padding: 5px;
            background-color: cyan;
            margin: 5px;
        }
        .pagination .page.active{
            background-color: brown;
            color: white;
        }
    </style>
</head>
<body>
    <ul>
        {% for item in li %}
            {% include 'li.html' %}
        {% endfor %}
    </ul>

    <div class="pagination">
        {{ page_str }}
    </div>
</body>
</html>
user_list.html

2.二、新增utils目錄,建立分頁工具pagination.py文件。

from django.utils.safestring import mark_safe  # 導入mark_safe函數


class Page:
    def __init__(self, current_page, data_count, per_page_count=10, pager_num=7):
        self.current_page = current_page  # 當前頁
        self.data_count = data_count      # 總頁數
        self.per_page_count = per_page_count   # 每頁顯示數據
        self.pager_num = pager_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)   # 內置函數divmod 可以整除返回True,不能整除返回False
        if y:
            v += 1
        return v

    def page_str(self, base_url):
        """
        定義分頁規則
        :param base_url:
        :return:
        """
        page_list = []

        if self.total_count < self.pager_num:
            start_index = 1
            end_index = self.total_count + 1
        else:
            if self.current_page <= (self.pager_num + 1) / 2:
                start_index = 1
                end_index = self.pager_num + 1
            else:
                start_index = self.current_page - (self.pager_num - 1) / 2
                end_index = self.current_page + (self.pager_num + 1) / 2
                if (self.current_page + (self.pager_num - 1) / 2) > self.total_count:
                    end_index = self.total_count + 1
                    start_index = self.total_count - self.pager_num + 1

        if self.current_page == 1:
            prev = '<a class="page" href="javascript:void(0);">上一頁</a>'
        else:
            prev = '<a class="page" 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 class="page" href="%s?p=%s">%s</a>' % (base_url, i, i)
            page_list.append(temp)

        if self.current_page == self.total_count:
            nex = '<a class="page" href="javascript:void(0);">下一頁</a>'
        else:
            nex = '<a class="page" href="%s?p=%s">下一頁</a>' % (base_url, self.current_page + 1,)
        page_list.append(nex)

        jump = """
        <input type='text'  /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
        <script>
            function jumpTo(ths,base){
                var val = ths.previousSibling.value;
                location.href = base + val;
            }
        </script>
        """ % (base_url,)

        page_list.append(jump)
        # django從view向template傳遞HTML字符串的時候,django默認不渲染此HTML,緣由是爲了防止這段字符串裏面有惡意攻擊的代碼(XSS)
        # mark_safe這個函數就是確認這段HTML字符串是安全的,Django會纔會渲染此HTML
        page_str = mark_safe("".join(page_list))

        return page_str
pagination.py

2.三、app下的views.py:

from django.shortcuts import render
from utils import pagination

LIST = []
for i in range(500):
    LIST.append(i)


def user_list(request):
    current_page = request.GET.get('p', 1)
    current_page = int(current_page)

    # val = request.COOKIES.get('per_page_count', 10)
    # val = int(val)
    page_obj = pagination.Page(current_page, len(LIST))

    data = LIST[page_obj.start:page_obj.end]

    page_str = page_obj.page_str("/app1/user_list/")

    return render(request, 'user_list.html', {'li': data, 'page_str': page_str})
views.py

 

 

2、Cookie

Cookie 是在 HTTP 協議下,服務器或腳本能夠維護客戶工做站上信息的一種方式。Cookie 是由 Web 服務器保存在用戶瀏覽器(客戶端)上的小文本文件,它能夠包含有關用戶的信息。不管什麼時候用戶連接到服務器,Web 站點均可以訪問 Cookie 信息,所以用戶不用每次登錄都須要輸入帳號密碼。

一、獲取Cookie:

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    """ 
  參數:
        default: 默認值
           salt: 加密鹽
        max_age: 後臺控制過時時間
    """

二、設置Cookie:

rep = HttpResponse(...) 或 rep = render(request, ...) #建立對象
 
rep.set_cookie(key,value,...) #明文Cookie設置方式
rep.set_signed_cookie(key,value,salt='加密鹽',...) #加密加鹽Cookie設置方式
    """
    參數:
        key,              鍵
        value='',         值
        max_age=None,     超時時間  
        expires=None,     超時時間(IE requires expires, so set it if hasn't been already.)
        max_age與expires的區別:max_age用秒設置超時時間,N秒後失效,expires用datetime設置超時時間,到截至時間後失效
        path='/',         Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問
        domain=None,      Cookie生效的域名
        secure=False,     https傳輸
        httponly=False    只能http協議傳輸,當httponly=True時,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)
    """

三、前端頁面操做Cookie

因爲Cookie保存在客戶端的電腦上,因此,JavaScript和jquery也能夠操做Cookie。

JavaScript操做Cookie:
#獲取cookie並賦值給變量
var strCookie=document.cookie
#修改cookie中的id值
document.cookie="id=88";
#設置終止時間
###獲取當前時間
var date=new Date();
var expireDays=10;
###將date設置爲10天之後的時間
date.setTime(date.getTime()+expireDays*60*1000);
###將id和name兩個cookie設置爲10天后過時
document.cookie="id=77; name=bill; expires="+date.toUTCString();


Jquery操做Cookie:
相對於JS操做cookie,Jquery操做Cookie就簡單不少
<script src='/static/js/jquery.cookie.js'></script>   #導入jquery.cookie.js文件,此文件在官網下載
$.cookie("list_pager_num", 30,{ path: '/' }); 

四、根據cookie值顯示定製條數示例:

在上面自定義分頁示例的基礎上,根據cookie值進行定製條數數據顯示。

 4.一、templates下的模板:

<li>{{ item }}</li>
li.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .pagination .page{
            display: inline-block;
            padding: 5px;
            background-color: cyan;
            margin: 5px;
        }
        .pagination .page.active{
            background-color: brown;
            color: white;
        }
    </style>
</head>
<body>
    <ul>
        {% for item in li %}
            {% include 'li.html' %}
        {% endfor %}
    </ul>

    <div>
        <select id="ps" onchange="changePageSize(this)">
            <option value="10">10</option>
            <option value="30">30</option>
            <option value="50">50</option>
            <option value="100">100</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>
        //將選擇框的值設置爲cookie,在Views中就能夠接收cookie
        function changePageSize(ths){
            var v = $(ths).val();
            $.cookie('per_page_count',v);
            location.reload(); //頁面從新加載
        }
        //將多選框的值更改成最新的值
         $(function(){
                var v = $.cookie('per_page_count');
                $('#ps').val(v);
        });

    </script>
</body>
</html>
user_list.html

4.二、utils目錄下pagination.py文件

from django.utils.safestring import mark_safe  # 導入mark_safe函數


class Page:
    def __init__(self, current_page, data_count, per_page_count=10, pager_num=7):
        self.current_page = current_page  # 當前頁
        self.data_count = data_count      # 總頁數
        self.per_page_count = per_page_count   # 每頁顯示數據
        self.pager_num = pager_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)   # 內置函數divmod 可以整除返回True,不能整除返回False
        if y:
            v += 1
        return v

    def page_str(self, base_url):
        """
        定義分頁規則
        :param base_url:
        :return:
        """
        page_list = []

        if self.total_count < self.pager_num:
            start_index = 1
            end_index = self.total_count + 1
        else:
            if self.current_page <= (self.pager_num + 1) / 2:
                start_index = 1
                end_index = self.pager_num + 1
            else:
                start_index = self.current_page - (self.pager_num - 1) / 2
                end_index = self.current_page + (self.pager_num + 1) / 2
                if (self.current_page + (self.pager_num - 1) / 2) > self.total_count:
                    end_index = self.total_count + 1
                    start_index = self.total_count - self.pager_num + 1

        if self.current_page == 1:
            prev = '<a class="page" href="javascript:void(0);">上一頁</a>'
        else:
            prev = '<a class="page" 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 class="page" href="%s?p=%s">%s</a>' % (base_url, i, i)
            page_list.append(temp)

        if self.current_page == self.total_count:
            nex = '<a class="page" href="javascript:void(0);">下一頁</a>'
        else:
            nex = '<a class="page" href="%s?p=%s">下一頁</a>' % (base_url, self.current_page + 1,)
        page_list.append(nex)

        jump = """
        <input type='text'  /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
        <script>
            function jumpTo(ths,base){
                var val = ths.previousSibling.value;
                location.href = base + val;
            }
        </script>
        """ % (base_url,)

        page_list.append(jump)
        # django從view向template傳遞HTML字符串的時候,django默認不渲染此HTML,緣由是爲了防止這段字符串裏面有惡意攻擊的代碼(XSS)
        # mark_safe這個函數就是確認這段HTML字符串是安全的,Django會纔會渲染此HTML
        page_str = mark_safe("".join(page_list))

        return page_str
pagination.py

4.三、app下的views.py:

def cookie(request):
    #
    # request.COOKIES
    # request.COOKIES['username111']
    request.COOKIES.get('username111')

    response = render(request,'index.html')
    response = redirect('/index/')
    # 設置cookie,關閉瀏覽器失效
    response.set_cookie('key',"value")
    # 設置cookie, N秒只有失效
    response.set_cookie('username111',"value",max_age=10)
    # 設置cookie, 截止時間失效
    import datetime
    current_date = datetime.datetime.utcnow()
    current_date = current_date + datetime.timedelta(seconds=5)
    response.set_cookie('username111',"value",expires=current_date)
    response.set_cookie('username111',"value",max_age=10)

    # request.COOKIES.get('...')
    # response.set_cookie(...)
    obj = HttpResponse('s')

    obj.set_signed_cookie('username',"kangbazi",salt="asdfasdf")
    request.get_signed_cookie('username',salt="asdfasdf")

    return response
views.py

五、cookie模擬登錄示例:

5.一、templates下模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form action="/login/" method="POST">
        <input type="text" name="username" placeholder="用戶名" />
        <input type="password" name="pwd" placeholder="密碼" />
        <input type="submit" />
    </form>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>歡迎登陸:{{ current_user }}</h1>
</body>
</html>
home

5.二、views.py:

user_info = {
    'dachengzi': {'pwd': "123123"},
    'kanbazi': {'pwd': "kkkkkkk"},
}
def login(request):
    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)
        if not dic:
            return render(request,'login.html')
        if dic['pwd'] == p:
            res = redirect('/home/')
            # res.set_cookie('username111',u,max_age=10)   #設置cookie N秒後失效 
            # import datetime
            # current_date = datetime.datetime.utcnow()
            # current_date = current_date + datetime.timedelta(seconds=5)
            # res.set_cookie('username111',u,expires=current_date)      #設置cookie 到截至時間後失效 
            res.set_cookie('username111',u)
            res.set_cookie('user_type',"asdfjalskdjf",httponly=True) # 只能http協議傳輸,當httponly=True時,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)
            return res
        else:
            return render(request,'login.html')
views.py

六、CBV和FBV用戶認證裝飾器

6.一、FBV (Function Base VIew)在view(視圖)中裝飾器編寫邏輯:

def auth(func):
    def inner(reqeust,*args,**kwargs):
        v = reqeust.COOKIES.get('username111')
        if not v:
            return redirect('/login/')
        return func(reqeust, *args,**kwargs)
    return inner

@auth
def index(reqeust):
    # 獲取當前已經登陸的用戶
    v = reqeust.COOKIES.get('username111')
    return render(reqeust,'index.html',{'current_user': v})

6.二、CBV(Class Base Viev)在view(視圖)中裝飾器編寫邏輯:

from django import views
from django.utils.decorators import method_decorator  #導入method_decorator函數,此函數時Django工具包中用於視圖中類的裝飾器函數

def auth(func):
    def inner(reqeust,*args,**kwargs):
        v = reqeust.COOKIES.get('username111')
        if not v:
            return redirect('/login/')
        return func(reqeust, *args,**kwargs)
    return inner


@method_decorator(auth,name='dispatch') #第三種裝飾方法,在類上添加上裝飾器
class Order(views.View):

    # @method_decorator(auth)  #第二種裝飾方法,在dispatch函數上添加裝飾器,由於dispatch函數會在類中全部函數執行前先行執行一遍
    # def dispatch(self, request, *args, **kwargs):
    #     return super(Order,self).dispatch(request, *args, **kwargs)

    # @method_decorator(auth)  #第一種裝飾方法,在須要裝飾的上添加裝飾器
    def get(self,reqeust):
        v = reqeust.COOKIES.get('username111')
        return render(reqeust,'index.html',{'current_user': v})

    def post(self,reqeust):
        v = reqeust.COOKIES.get('username111')
        return render(reqeust,'index.html',{'current_user': v})

  

 

3、session

Session存儲在服務器端,通常放置在服務器的內存中(爲了高速存取),Sessinon在用戶訪問第一次訪問服務器時建立,須要注意只有訪問JSP、Servlet等程序時纔會建立Session,只訪問HTML、IMAGE等靜態資源並不會建立Session,可調用request.getSession(true)強制生成Session。

Django中默認支持Session,其內部提供了5種類型的Session供開發者使用:

  • 數據庫(默認)
  • 緩存
  • 文件
  • 緩存+數據庫
  • 加密cookie
 1 Django默認支持Session,而且默認是將Session數據存儲在數據庫中,即:django_session 表中。
 2  
 3 a. 配置 settings.py
 4  
 5     SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默認)
 6      
 7     SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
 8     SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路徑(默認)
 9     SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默認)
10     SESSION_COOKIE_SECURE = False                            # 是否Https傳輸cookie(默認)
11     SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http傳輸(默認)
12     SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默認)
13     SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否關閉瀏覽器使得Session過時(默認)
14     SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次請求都保存Session,默認修改以後才保存(默認)
15  
16  
17  
18 b. 使用
19  
20     def index(request):
21         # 獲取、設置、刪除Session中數據
22         request.session['k1']
23         request.session.get('k1',None)
24         request.session['k1'] = 123
25         request.session.setdefault('k1',123) # 存在則不設置
26         del request.session['k1']
27  
28         # 全部 鍵、值、鍵值對
29         request.session.keys()
30         request.session.values()
31         request.session.items()
32         request.session.iterkeys()
33         request.session.itervalues()
34         request.session.iteritems()
35  
36  
37         # 用戶session的隨機字符串
38         request.session.session_key
39  
40         # 將全部Session失效日期小於當前日期的數據刪除
41         request.session.clear_expired()
42  
43         # 檢查 用戶session的隨機字符串 在數據庫中是否
44         request.session.exists("session_key")
45  
46         # 刪除當前用戶的全部Session數據
47         request.session.delete("session_key")
48  
49         request.session.set_expiry(value)
50             * 若是value是個整數,session會在些秒數後失效。
51             * 若是value是個datatime或timedelta,session就會在這個時間後失效。
52             * 若是value是0,用戶關閉瀏覽器session就會失效。
53             * 若是value是None,session會依賴全局session失效策略。
數據庫Session
 1 a. 配置 settings.py
 2  
 3     SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
 4     SESSION_CACHE_ALIAS = 'default'                            # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置
 5  
 6  
 7     SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
 8     SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路徑
 9     SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
10     SESSION_COOKIE_SECURE = False                             # 是否Https傳輸cookie
11     SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http傳輸
12     SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
13     SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否關閉瀏覽器使得Session過時
14     SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次請求都保存Session,默認修改以後才保存
15  
16  
17  
18 b. 使用
19  
20     同上
緩存Session
 1 a. 配置 settings.py
 2  
 3     SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
 4     SESSION_FILE_PATH = None                                    # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
 5  
 6  
 7     SESSION_COOKIE_NAME = "sessionid"                          # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
 8     SESSION_COOKIE_PATH = "/"                                  # Session的cookie保存的路徑
 9     SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
10     SESSION_COOKIE_SECURE = False                               # 是否Https傳輸cookie
11     SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http傳輸
12     SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
13     SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否關閉瀏覽器使得Session過時
14     SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次請求都保存Session,默認修改以後才保存
15  
16 b. 使用
17  
18     同上
文件Session
1 數據庫用於作持久化,緩存用於提升效率
2  
3 a. 配置 settings.py
4  
5     SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
6  
7 b. 使用
8  
9     同上
緩存+數據庫Session
1 a. 配置 settings.py
2      
3     SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎
4  
5 b. 使用
6  
7     同上
加密cookie Session

 更多session參考:參考一參考二

一、session免密登陸+10秒超時示例:

1.一、templates 下的模板文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form action="/login/" method="POST">
        <input type="text" name="user" />
        <input type="text" name="pwd" />
        <input type="checkbox" name="rmb" value="1" /> 10秒免登陸
        <input type="submit" value="提交" />
        <input id="btn1" type="button" value="按鈕" />
        <input id="btn2" type="button" value="按鈕" />
    </form>

    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>歡迎登陸:{{ username }}, {{ request.session.username }}</h1>
    <a href="/logout/">註銷</a>
</body>
</html>
index.html

 1.二、views.py:

from django.shortcuts import render,redirect,HttpResponse

def login(request):
    if request.method == "GET":
        return render(request,'login.html')
    elif request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user == 'root' and pwd == "123":
            # session中設置值  Django自動產生4步操做(一、生成隨機字符串 二、寫到用戶瀏覽器cookie 三、保存在session中 四、在隨機字符串對應字典中設置相應值)
            request.session['username'] = user
            request.session['is_login'] = True
            if request.POST.get('rmb', None) == '1':
                # 超時時間
                request.session.set_expiry(10)
            return redirect('/index/')
        else:
            return render(request,'login.html')

def index(request):
    # session中獲取值
    if request.session.get('is_login', None):
        # {'username': request.session['username']}這個字典數據其實能夠不用傳遞,由於request自己就包含了session值,
        # 在HTML中能夠直接經過request.session.username獲取用戶名
        return render(request, 'index.html', {'username': request.session['username']})
    else:
        return HttpResponse('gun')

# 註銷
def logout(request):
    # del request.session['username']  # 刪除一個指定session用戶
    request.session.clear()            # 清楚所有session用戶
    return redirect('/login/')
views.py

 注、在運行Django工程示例前須要運行以下命令,生成表結構,session會默認保存在db.sqlite3數據庫文件中。

python3 manage.py  makemigrations #至關於在該app的migrations目錄,記錄下該app下modes.py全部表結構類型的改動(普通增刪改查不記錄)
python3 manage.py  migrate        #將剛剛對於表結構的改動做用至數據庫

 

 

4、CSRF

CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站腳本(XSS),但它與XSS很是不一樣,XSS利用站點內的信任用戶,而CSRF則經過假裝來自受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊每每不大流行(所以對其進行防範的資源也至關稀少)和難以防範,因此被認爲比XSS更具危險性。

以前的Django博文,都是基於在settings.py文件中,註釋掉CSRF中間件進行的。

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

注:如今開始以後的博文都是去掉CSRF中間件註釋進行演示。

django中設置防跨站請求僞造功能有分爲全局和局部: 

全局:
  中間件 django.middleware.csrf.CsrfViewMiddleware

局部:
  from django.views.decorators.csrf import csrf_exempt,csrf_protect
  @csrf_protect,爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置全局中間件。
  @csrf_exempt,取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件。

一、生成csrf_token:

在Django中能夠經過{% csrf_token %} 生成csrftoken來防範CSRF攻擊,可是要在後續的request請求中須要帶上csrftoken參數才能經過CSRF中間件防護機制,進入view視圖中進行處理。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form action="/login/" method="POST">
        <!--在Django中可經過%配合csrf_token字段可生成csrf_token字符串,會在form表單中生成一個隱藏的input框以下:
        <input type="hidden" name="csrfmiddlewaretoken" value="6CAO0tE8oqIsehJFR9VojmS307XRfK91GkxRHutKvwj5nSQgI6KDZZL4hLkAorNo">
        還會在cookie中生成{csrftoken:gQgbSGTiXtnqTeKD0jRbq6ZGsrdiWiJZQydezHIU4zY32PReRgGq6JSHJ5A15Znm}-->
        {% csrf_token %}
        <input type="text" name="user" />
        <input type="text" name="pwd" />
        <input type="checkbox" name="rmb" value="1" /> 10秒免登陸
        <input type="submit" value="提交" />
    </form>
    </script>
</body>
</html>
生成csrftoken

 二、csrf_token 提交給後臺的三種方式:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form action="/login/" method="POST">
 9         <!--在Django中可經過%配合csrf_token字段可生成csrf_token字符串,會在form表單中生成一個隱藏的input框以下:
10         <input type="hidden" name="csrfmiddlewaretoken" value="6CAO0tE8oqIsehJFR9VojmS307XRfK91GkxRHutKvwj5nSQgI6KDZZL4hLkAorNo">
11         還會在cookie中生成{csrftoken:gQgbSGTiXtnqTeKD0jRbq6ZGsrdiWiJZQydezHIU4zY32PReRgGq6JSHJ5A15Znm}-->
12         {% csrf_token %}
13         <input type="text" name="user" />
14         <input type="text" name="pwd" />
15         <input type="checkbox" name="rmb" value="1" /> 10秒免登陸
16         <input type="submit" value="提交" />                                <!-- 第一種提交csrf_token的方式 經過from表單的形式-->
17         <input id="btn1" type="button" value="按鈕" />
18         <input id="btn2" type="button" value="按鈕" />
19     </form>
20 
21     <script src="/static/jquery-1.12.4.js"></script>
22     <script src="/static/jquery.cookie.js"></script>
23     <script>
24       //  第二種提交csrf_token的方式   在每一個ajax請求以前,將cookie中的csrftoken值添加至請求頭中,ajaxSetup相似於unittest框架中的setup,在每一個case運行以前運行一遍
25         $(function(){
26             $.ajaxSetup({
27                 beforeSend: function(xhr,settings){   // xhr 是XMLHttpRequest()對象,settings是Django的配置文件,settings.py每次運行都會將settings加載在內存之中
28 
29 
30                     xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'));
31                 }
32             });
33 
34             // <!-- 第三種提交csrf_token的方式   經過ajax形式將cookie中的csrftoken值添加至請求頭中-->
35             // <!-- 可是第三種提交方式很差的地方就是須要不斷的添加ajax請求,有一個提交按鈕,就要新增一個ajax請求-->
36             $('#btn1').click(function () {
37                 $.ajax({
38                     url: '/login/',
39                     type:"GET",
40                     data: {'user': 'root', 'pwd': '123'},
41                     // headers: {'X-CSRFtoken': $.cookie('csrftoken')},  //X-CSRFtoken 這key是固定的不能改變
42                     success:function(arg){
43 
44                     }
45                 })
46             });
47         })
48     </script>
49 </body>
50 </html>
三種方式

 注:解釋 ajax 將csrftoken值添加至請求頭中,爲何對應的key是 X-CSRFtoken:

from django.conf import settings
print(settings.CSRF_HEADER_NAME)

#輸出打印結果  HTTP_X_CSRFTOKEN
View Code

經過打印結果發現值是 HTTP_X_CSRFTOKEN,這個就是csrftoken請求頭對應的key,HTTP是由於Django會默認將收到的每一個請求都會加上HTTP的緣故。所以對應的真實key是X_CSRFTOKEN,可是若是真的就把請求頭中的key寫成X_CSRFTOKEN的話,後臺是接收不到的,由於沒法識別下劃線_,所以須要將X_CSRFTOKEN寫成X-CSRFTOKEN。(X-CSRFTOKEN這個做爲key是能夠請求的,可是爲了命名規範會寫成X-CSRFtoken)

三、根據請求方式決定是否提交csrftoken值

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% csrf_token %}
  
    <input type="button" onclick="Do();"  value="Do it"/>
  
    <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
    <script src="/static/plugin/jquery/jquery.cookie.js"></script>
    <script type="text/javascript">
        var csrftoken = $.cookie('csrftoken');
  
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
        function Do(){
  
            $.ajax({
                url:"/app01/test/",
                data:{id:1},
                type:'POST',
                success:function(data){
                    console.log(data);
                }
            });
  
        }
    </script>
</body>
</html>
View Code

更多CSRF參考:點擊

相關文章
相關標籤/搜索