day18-session、ajax、中間件、分頁、orm多對多

day18  2018-08-19

1. 講課內容:
    1. session:https://www.cnblogs.com/liwenzhou/p/8343243.html
        1. Cookie是保存在瀏覽器端的鍵值對
           用來解決HTTP請求是無狀態的
        
        2. Django裏面使用Cookie
            1. 設置Cookie
                1. 回覆響應時設置的
                    rep = HttpResponse("OK")
                    rep.set_cookie("key", "value", max_age=超時時間(秒))
                    rep.set_signed_cookie("key", "value", salt="", max_age=超時時間(秒))
            2. 獲取Cookie
                請求來的時候從請求中找cookie
                1. request.COOKIES.get("key")
                2. request.get_signed_cookie("key", default="", salt="")
                    
        3. 爲何要有session
            1. Cookied額缺點:
                1. 數據量只有4096
                2. 數據都保存在客戶端(瀏覽器)上,不安全

            2. Session
                保存在服務端的鍵值對
                
                1. 請求來了以後,仍是生成隨機字符串
                2. 以隨機字符串爲key,在服務端生成一個大字典,真正保存數據是value
                3. 把隨機字符串以cookie的形式回覆給瀏覽器
                
                4. 下一次請求再來的時候,會攜帶上一步的隨機字符串
                5. 從請求中拿到隨機字符串,
                6. 去後端以 該隨機字符串爲key找對應的value
                7. value裏面存的就是真正有用的數據
                
            3. Django中如何使用Session
                1. 不管設置Session仍是獲取Session都是針對request對象來操做
                
                2. 設置Session
                    request.session["key"] = "value"
                3. 獲取session
                    request.session.get("key")
                
                4. 其餘經常使用命令
                    1. # 將全部Session失效日期小於當前日期的數據刪除
                        request.session.clear_expired()
                    2. # 刪除當前的會話數據並刪除會話的Cookie。
                        request.session.flush() 
                    
                    3. 設置超時時間
                    request.session.set_expiry(7)
                
                5. 經常使用配置項(寫在Settings.py中)
                    # 全局配置session超時時間
                    SESSION_COOKIE_AGE = 60 * 60 * 24 * 2

                    # 是否每次請求都刷新session超時時間
                    SESSION_SAVE_EVERY_REQUEST = True
                    
                    
    
    2. 分頁:https://www.cnblogs.com/liwenzhou/p/8343243.html最下面
        1. 如何在單獨的一個腳本文件中使用Django的一些變量或方法
        2. bulk_create()   Django ORM批量建立的一個方法
        
        分頁:
            每頁顯示10條
            
            1             0-10
            2             10-20
            3             20-30
            
            n             (n-1)*10-n*10
        
    
    3. 中間件:https://www.cnblogs.com/liwenzhou/p/8761803.html
        1. 何時使用中間件?
            當須要在全局改變Django框架的輸入輸出時
        2. 中間件不宜添加過多,功能過於複雜
            不然會增長請求的響應時間
                
        3. Django如何使用
            1. 五個方法(三個經常使用)
                主要記憶:執行時間、執行順序、參數和返回值
                1. process_request(self,request)
                    1. 執行時間
                        在執行視圖函數以前執行
                    2. 執行順序
                        按照註冊的順序執行
                    3. 參數和返回值
                        1. request參數和視圖函數中是同一個對象
                        2. 返回值:
                            1. 返回None:請求繼續日後執行
                            2. 返回響應對象:請求就結束了,要返回響應了
                2. process_response(self, request, response)        
                    1. 執行時間
                        視圖函數執行以後(拿到響應對象以後)
                    
                    2. 執行順序
                        按照註冊的倒序執行
                    3. 參數和返回值
                        1. 參數:request請求對象
                                 response:響應對象
                        2. 返回值:
                            只能返回響應對象
                                1. 返回默認的
                                2. 本身生成一個響應對象返回    
                3. process_view(self, request, view_func, view_args, view_kwargs)
                    1. 執行時間
                        視圖函數以前,在urls.py找到將要執行的視圖函數以後
                    2. 執行順序
                        註冊的順序執行
                        
                    3. 參數和返回值
                        1. 參數:
                            1. request: 請求對象
                            2. view_func:將要執行的視圖函數
                        2. 返回值:
                            1. 返回None:繼續日後執行
                            2. 返回響應對象,直接跳出,按照process_response方法的順序執行
                
                有條件觸發:
                4. process_template_response(self,request,response)
                    1. 執行時間:
                        1. 視圖函數以後,而且返回的響應對象是要有render方法
                    2. 執行順序:
                        1. 按照註冊的倒序執行
                    3. 返回值:
                        1. 對傳遞過來的響應對象,調用其render方法,把返回值向後繼續傳遞
                5. process_exception(self, request, exception)
                    1. 執行時間:
                        1. 當視圖函數中拋出異常的時候才執行
                    2. 執行順序:
                        1. 註冊的倒序
                    3. 參數和返回值
                        exception:視圖函數中拋出的異常
                        返回響應對象,就跳出按照process_response方法的順序執行
    
            2. 額外補充
                1. 反射      --> 由一個字符串找到方法、函數(可調用對象)
                2. importlib --> 由字符串動態導入   **本身回去查
            3. 示例:
                限制用戶訪問我網站的頻率,一分鐘最多訪問3次
                15:52:13 15:52:11 15:52:04 15:52:01
                {
                    '11.12.13.14': [15:52:11, 15:52:04, 15:52:01]
                }
                
    4. ORM(多對多)
        1. ORM多對多字段
            # 多對多,自動幫咱們在數據庫創建第三張關係表
            books = models.ManyToManyField(to='Book', related_name="authors")
            參數:
                - to:表示和哪張表創建多對多的關係
                - related_name:表示返鄉查詢時使用的那個字段名,默認反向查詢時使用表名_set的方式
        
        2. 多對多字段的方法
            1. 查詢
                .all()  --> 多對多查詢的方法,
            
            2. 刪除
            
            3. 添加新做者
                1. 當form表單提交的數據是列表(多選的select\多選的checkbox)取值?
                    request.POST.getlist("hobby")
    
                2. .set([id1,id2,...])  參數是一個列表  --> 刪除原來的設置新的
                3. .add(id值)                           --> 在原來的基礎上增長新的紀錄
    
    
        3. 13條
            1. 返回QuerySet類型的
                1. all()
                2. filter()
                3. exclude()
                4. order_by()
                5. reverse()
                6. distinct()
                
                7. values()      -> QuerySet中是字典類型
                8. values_list() -> QuerySet中是元祖類型
                
            2. 返回具體對象的
                1. get()
                2. first()
                3. last()
                
            3. 返回數字
                1. count()
            4. 返回布爾值
                1. exist()
        
    5. ajax:https://www.cnblogs.com/liwenzhou/p/8718861.html
        1. 目前已知瀏覽器和服務端發請求的方式
            1. 瀏覽器地址欄 輸入url直接回車   GET
            2. a標籤                          GET
            3. form表單                       GET/POST
            4. ajax                           GET/POST
            
            
            ajax的特色:
                優勢:
                    1. 偷偷發請求,用戶無感知
                    2. 局部刷新  相對於其餘請求方式而言,返回的數據量小  
                    3. 同一個頁面能夠發送屢次請求     異步
                缺點:
                    1. 若是濫用,對服務端的壓力比較大
                    
            ajax的使用:
                jQuery版:
                    導入jQuery
                    $.ajax({
                        url: "往哪裏發請求",
                        type: "發送請求的類型",
                        data: {
                        
                        },
                        success:function(res){
                            
                        }
                    })
                    
            ajax注意事項:
                data
                    
    
    6. jQuery:https://www.cnblogs.com/liwenzhou/p/8178806.html
        1. 選擇器
            1. 基本選擇器
                1. id
                2. 類
                3. 標籤
                4. 屬性
                5. 組合
            
            2. 層級選擇器
                1. 後代選擇器
                2. 毗鄰選擇器
                3. 兒子選擇器
        2. .text()
            1. 獲取標籤的文本內容            $("div").text()         --> 默認取全部div的文本內容
            2. 有參數表示 設置標籤的文本內容 $("div").text(‘哈哈’)   --> 設置全部div標籤的文本爲哈哈      
        3. .html()
            1. 獲取標籤的html內容            $("div").html()         --> 默認取第一個div的html內容
            2. 有參數表示 設置標籤的html內容 $("div").html(‘哈哈’)   --> 設置全部div標籤的html內容爲哈哈  
            
        4. val()
            1. 獲取input標籤的值            $("input").val()         --> 默認取第一個input的值
            2. 有參數表示 設置input標籤的值 $("input").val(666)      --> 設置全部input標籤的值爲666 
        

    
        AJAX上傳文件,下週再講
    5. Form & ModelForm(下週再講)
    
    
技術的提高只是量的積累,思想的提高才是質的飛躍。
在公司混:政治正確纔是最重要的!

    
2. 練習題:
    1. django請求生命週期
    2. csrf原理
    3. ORM和原生SQL區別?
    4. django中裝飾器和中間件的應用場景?
    5. 爲何要使用母板?
    6. ORM查詢示例:
        表結構:
            出版社表:
                ID   名稱
            圖書表:
                ID   書名稱    價格     出版社ID

            做者表:
                ID   做者姓名

            做者和圖書關係表:
                ID   圖書ID    做業ID
        題目:
            1. 查詢alex出過的全部書籍的名字(多對多)
            2. 查詢alex的手機號
            3. 查詢人民出版社出版過的全部書籍的名字以及做者的姓名
            4. 統計每一本書的做者個數
            5. 統計不止一個做者的圖書
            6. 根據一本圖書做者數量的多少對查詢集 QuerySet進行排序
            7. 查詢各個做者出的書的總價格


3. 做業:主機管理【03】:業務線管理
    1. 基於django建立表:
        用戶表:ID、用戶名、密碼
        業務線表:ID、名稱
        主機表:ID、主機名、密碼、業務線ID
        用戶和業務線關係表:ID、業務線ID、管理員ID
    2. 業務線管理:增刪改查(多對多)
    3. 使用模板和動態路由
    4. 主機管理使用CBV實現
    5. 套用BootStrap樣式

    採分點:
        練習題:20
        實現全部功能:70
        代碼寫的清晰、健壯、可擴展:10
課上筆記
# 做業:引入框架模板----重要!!!2-3天---1.下次做業添加  0821 ok
# 新增功能:分頁 ok

# 需優化:1.cookie和session ---界面跳轉存在問題?
# 2.添加ajax局部刷新??
# 3.中間件???
# 4.刪除確認

# 重點關注一下 正向查詢、反向查詢、、、、
# cookie
# github
# 菜鳥教程---python,,,100例練習


'''
0809回顧
cookie


'''

'''
1.session
爲何要有session?
cookie的保存內容有限,只有4096;數據都保存在瀏覽器
原理
django中如何使用?


內容保存在數據庫的django_session中,k,v,超時時間
session把設置的kv數據保存在server端,cookie是存放在瀏覽器端

刪除過時的session
book_list註銷

session版登陸,本身書寫--ok
全局配置session
2.分頁
在腳本中操做orm,批量建立數據,提交
insert_book:設置環境,引入,建立數據

頁面實現
問題解決:輸入字母顯示第一頁;輸入很大的數字,取最後一頁
前端中有向上取整?ceil?
頁面按鈕問題:1.按鈕能動態切換顯示
2.頁面最多顯示11個:選中的高亮顯示active,頁碼顯示正常不出現0、55等,數據少時
3.顯示首頁和尾頁
4.添加上一頁、下一頁:第一頁不能點擊上一頁;最後一頁同理
---------看分裝以前代碼views
5.封裝成類@property 將方法變爲屬性,調用時就不用加()啦
出版社分頁,使用分裝的類;;須要添加a標籤對象鏈接地址
"""
那是一個上午,
寫了一個分頁的功能,特地封裝成了一個類工具,blablabla...
"""


# 封裝分頁類
class MyPage(object):

    def __init__(self, current_page, total_count, url_prefix, per_page=10, max_show=11):
        """
        初始化一個我本身定義的分頁實例
        :param current_page: 當前頁碼
        :param total_count: 總的數據量
        :param url_prefix: 分頁中a標籤的url前綴
        :param per_page: 每個顯示多少條數據
        :param max_show: 頁面上最多顯示多少個頁碼
        """
        self.total_count = total_count
        self.per_page = per_page
        self.max_show = max_show
        self.url_prefix = url_prefix

        # 最多顯示頁碼數的一半
        half_show = max_show // 2
        #    由於URL取到的參數是字符串格式,須要轉換成int類型
        try:
            current_page = int(current_page)
        except Exception as e:
            # 若是輸入的頁碼不是正經頁碼,默認展現第一頁
            current_page = 1
        # 求總共須要多少頁顯示
        total_page, more = divmod(total_count, per_page)
        if more:
            total_page += 1
        # 若是輸入的當前頁碼數大於總數據的頁碼數,默認顯示最後一頁
        if current_page > total_page:
            current_page = total_page
        self.current_page = current_page

        # 計算一下顯示頁碼的起點和終點
        show_page_start = current_page - half_show
        show_page_end = current_page + half_show
        # 特殊狀況特殊處理
        # 1. 當前頁碼 - half_show <= 0
        if current_page - half_show <= 0:
            show_page_start = 1
            show_page_end = max_show
        # 2. 當前頁碼數 + hale_show >= total_page
        if current_page + half_show >= total_page:
            show_page_end = total_page
            show_page_start = total_page - max_show + 1
        # 3. 總共須要的頁碼數 < max_show
        if total_page < max_show:
            show_page_start = 1
            show_page_end = total_page

        self.show_page_start = show_page_start
        self.show_page_end = show_page_end
        self.total_page = total_page

    # 數據切片的起點
    @property
    def start(self):
        return (self.current_page - 1) * self.per_page

    # 數據切片的終點
    @property
    def end(self):
        return self.current_page * self.per_page

    # 分頁的html代碼
    def page_html(self):
        tmp = []
        page_html_start = '<nav aria-label="Page navigation" class="text-center"><ul class="pagination">'
        page_html_end = '</ul></nav>'
        tmp.append(page_html_start)
        # 添加一個首頁
        tmp.append('<li><a href="/{}?page=1">首頁</a></li>'.format(self.url_prefix))
        # 添加一個上一頁
        # 噹噹前頁是第一頁的時候不能再點擊上一頁
        if self.current_page - 1 <= 0:
            tmp.append(
                '<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>')
        else:
            tmp.append(
                '<li><a href="/{}?page={}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>'.format(
                    self.url_prefix, self.current_page - 1))
        # for循環添加要展現的頁碼
        for i in range(self.show_page_start, self.show_page_end + 1):
            # 若是for循環的頁碼等於當前頁碼,給li標籤加一個active的樣式
            if self.current_page == i:
                tmp.append('<li class="active"><a href="/{1}?page={0}">{0}</a></li>'.format(i, self.url_prefix))
            else:
                tmp.append('<li><a href="/{1}?page={0}">{0}</a></li>'.format(i, self.url_prefix))
        # 添加一個下一頁
        # 當前 當前頁已是最後一頁,應該不讓下一頁按鈕能點擊
        if self.current_page + 1 > self.total_page:
            tmp.append(
                '<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&raquo;</span></a></li>')
        else:
            tmp.append(
                '<li><a href="/{}?page={}" aria-label="Previous"><span aria-hidden="true">&raquo;</span></a></li>'.format(
                    self.url_prefix, self.current_page + 1))
        # 添加一個尾頁
        tmp.append('<li><a href="/{}?page={}">尾頁</a></li>'.format(self.url_prefix, self.total_page))
        tmp.append(page_html_end)

        page_html = "".join(tmp)
        return page_html
分頁代碼
from django.shortcuts import render
from app01 import models
from utils import mypage

# Create your views here.


def book_list(request):
    # 查找到全部的書籍
    books = models.Book.objects.all()
    # 拿到總數據量
    total_count = books.count()
    # 從url拿到page參數
    current_page = request.GET.get("page", None)

    page_obj = mypage.MyPage(current_page, total_count, url_prefix="book_list", max_show=7)
    # 對總數據進行切片,拿到頁面顯示須要的數據
    data = books[page_obj.start:page_obj.end]
    page_html = page_obj.page_html()

    return render(request, "book_list.html", {"books": data, "page_html": page_html})


def publisher_list(request):
    publishers = models.Publisher.objects.all()
    total_count = publishers.count()
    current_page = request.GET.get("page")

    # 三行完成分頁功能
    page_obj = mypage.MyPage(current_page, total_count, url_prefix='publisher_list')
    data = publishers[page_obj.start:page_obj.end]
    page_html = page_obj.page_html()

    return render(request, "publisher_list.html", {"publishers": data, "page_html": page_html})
分頁應用

'''
# 註銷
def logout(request):
    # 清除session數據,讓cookie失效
    request.session.flush()
    return redirect("/login/")

'''
3.中間件

importlib本身學習--本身練習代碼
5個使用中間件的方法:
process_request(self,request)
process_response(self,request,response)
哈哈----是嘿嘿的相應哈哈
1-3必需要會;4-5瞭解便可

例子--利用中間件,作頻率限制;動態配置頻率限制


4.orm多對多
建立庫以後,有sqlite3數據庫,才能在session中存取數據
用戶輸入的值,不要用get,用filter

列表--刪除--增長-修改
form表單提交的數據是列表(多選的select、checkbox)時,取值request.POST.getlist()
.set([]) 參數是一個列表,重置
.add([]) 增長
最難的地方,判斷書默認選中。
第三張表自動封裝了保存更新方法。

跨表查詢--要掌握
1. 基於對象的查詢
1. 正向查
2. 反向查
2. 基於QuerySet的查詢
1. 正向查
2. 反向查

'''

'''
5.ajax

JSON.parse 反序列化 字符串----對象
1.json內容回顧: 老師博客中有圖

2.ajax:偷偷發請求,用戶無感知;局部刷新,返回的數據量小;同一個頁面能夠發送屢次請求缺點:若是濫用,對服務端壓力較大ajax使用:jquery版導入;坑:    多餘一層的數據要使用json.stringify    保存setupajax    ensure_csrf_cookie數據求和例子;用戶名校驗例子6.補充:jquery內容''''''下節:刪除確認-----------------------------AJAX上傳文件,下週再講---------------------   5. Form & ModelForm(下週再講)'''
相關文章
相關標籤/搜索