Django - Cookie、Session、自定義分頁和Django分頁器

2. 今日內容
    https://www.cnblogs.com/liwenzhou/p/8343243.html
    1. Cookie和Session
        1. Cookie

        服務端:
            1. 生成字符串
            2. 隨着響應將字符串回覆給瀏覽器
            3. 從瀏覽器發送的請求中拿到字符串

        cookie就是保存在瀏覽器上的字符串!!!
        每一次請求都會攜帶着cookie

        把要保存的信息都保存在用戶的瀏覽器上
        好處:
            服務端不用存,減輕了服務器壓力
        壞處:
            信息不安全


    Session:
        搭配Cookie使用

        Session本質上,保存在服務端的鍵值對。
        好處:
            用戶的信息都保存在服務端,安全
        壞處:
            數據都保存在服務端,存儲壓力比較大

    cookie和Session應用場景:
        登陸
        刷票限制
        保存用戶的瀏覽習慣

    Django中使用Session:
         獲取、設置、刪除Session中數據
        request.session['k1']
        request.session.get('k1',None)
        request.session['k1'] = 123
        request.session.setdefault('k1',123) # 存在則不設置


        # 刪除當前用戶的全部Session數據
        request.session.delete()

        request.session.set_expiry(value)
        * 若是value是個整數,session會在些秒數後失效。
        * 若是value是個datatime或timedelta,session就會在這個時間後失效。
        * 若是value是0,用戶關閉瀏覽器session就會失效。
        * 若是value是None,session會依賴全局session失效策略。

    CBV加裝飾器注意事項:
        要將函數裝飾器轉成方法裝飾器
        from django.utils.decorators import method_decorator
        @method_decorator(check_login)

    2. 分頁
        第幾頁  數據  索引
        1     1-10   0-10
        2     11-20  10-20
        3     21-30

----------------------------------------------
筆記
day 70 內容回顧

1.內容回顧
    https://www.cnblogs.com/liwenzhou/p/8343243.html
    1.cookie
        本質上就是保存在瀏覽器上得鍵值對
        爲了解決HTTP請求是無狀態得

        能夠用來作登陸 7天免登陸 瀏覽習慣 (每頁顯示多少條)
        Django 操做Cookie
            1.設置Cookie 是在response對象
                1.明文的
                    rep = 響應對象(基礎必備三件套)
                    rep.set_cookie(key,value,..)
                2.加鹽的
                    rep = 響應對象(基礎必備三件套)
                    rep.set_signed_cookie(key,value,salt='加密鹽)

            2.獲取Cookie 是在request對象
                1.明文的
                    request.COOKIES.get('key') / request.COOKIES['key']
                2.加鹽的
                   request.get_signed_cookie(key, default="默認值", salt='', max_age=None)

    2.session
        1.定義
            保存在服務器端的鍵值對,依賴與Cookie

        2.Django的session 操做
            1.設置session
                request.session['k1']
                request.session.setdefault('k1',123) # 存在則不設置
            2.獲取session
                request.session.get('k1',None)
                request.session['k1']
            3.刪除session
                del request.session['k1']
                註銷以後刪除用戶全部的session數據
                request.session.delete()
            4.將全部Session失效日期小於當前日期的數據刪除
                request.session.clear_expired()

            5.設置會話Session和Cookie的超時時間
                request.session.set_expiry(value)
                    * 若是value是個整數,session會在些秒數後失效。
                    * 若是value是個datatime或timedelta,session就會在這個時間後失效。
                    * 若是value是0,用戶關閉瀏覽器session就會失效。
                    * 若是value是None,session會依賴全局session失效策略。

        3.FBV和CBV
            CBV要加裝飾器須要用到method_decorator
            # 導入django 提供得工具 把函數裝飾器變成方法裝飾器
            from django.utils.decorators import method_decorator


    3.分頁
        1.自定義的分頁
            重在理解!
            編程思想的創建是一個積累的過程。不要着急!!,知道怎麼用
        2.Djangon自帶的分頁
            注意幾個屬性
筆記

1、Cookie

Cookie的由來javascript

你們都知道HTTP協議是無狀態的。css

無狀態的意思是每次請求都是獨立的,它的執行狀況和結果與前面的請求和以後的請求都無直接關係,它不會受前面的請求響應狀況直接影響,也不會直接影響後面的請求響應狀況。html

狀態能夠理解爲客戶端和服務器在某次會話中產生的數據,那無狀態的就覺得這些數據不會被保留。會話中產生的數據又是咱們須要保存的,也就是說要「保持狀態」。所以Cookie就是在這樣一個場景下誕生。java

什麼是Cookiepython

Cookie具體指的是一段小信息,它是服務器發送出來存儲在瀏覽器上的一組組鍵值對,下次訪問服務器時瀏覽器會自動攜帶這些鍵值對,以便服務器提取有用信息。mysql

Cookie的原理jquery

cookie的工做原理是:由服務器產生內容,瀏覽器收到請求後保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上Cookie,這樣服務器就能經過Cookie的內容來判斷這個是「誰」了。git

查看Cookiegithub

咱們使用Chrome瀏覽器,打開開發者工具。ajax

 

Django中操做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,...)
rep.set_signed_cookie(key,value,salt='加密鹽',...)

參數:

  • key, 鍵
  • value='', 值
  • max_age=None, 超時時間
  • expires=None, 超時時間(IE requires expires, so set it if hasn't been already.)
  • path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問
  • domain=None, Cookie生效的域名
  • secure=False, https傳輸
  • httponly=False 只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)

刪除Cookie

def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 刪除用戶瀏覽器上以前設置的usercookie值
    return rep

 

Cookie版登錄校驗

def check_login(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
            # 已經登陸的用戶...
            return func(request, *args, **kwargs)
        else:
            # 沒有登陸的用戶,跳轉剛到登陸頁面
            return redirect("/login/?next={}".format(next_url))
    return inner


def login(request):
    if request.method == "POST":
        username = request.POST.get("username")
        passwd = request.POST.get("password")
        if username == "xxx" and passwd == "123":
            next_url = request.GET.get("next")
            if next_url and next_url != "/logout/":
                response = redirect(next_url)
            else:
                response = redirect("/class_list/")
            response.set_signed_cookie("login", "yes", salt="SSS")
            return response
    return render(request, "login.html")

2、Session

Session的由來

Cookie雖然在必定程度上解決了「保持狀態」的需求,可是因爲Cookie自己最大支持4096字節,以及Cookie自己保存在客戶端,可能被攔截或竊取,所以就須要有一種新的東西,它能支持更多的字節,而且他保存在服務器,有較高的安全性。這就是Session。

問題來了,基於HTTP協議的無狀態特徵,服務器根本就不知道訪問者是「誰」。那麼上述的Cookie就起到橋接的做用。

咱們能夠給每一個客戶端的Cookie分配一個惟一的id,這樣用戶在訪問時,經過Cookie,服務器就知道來的人是「誰」。而後咱們再根據不一樣的Cookie的id,在服務器上保存一段時間的私密資料,如「帳號密碼」等等。

總結而言:Cookie彌補了HTTP無狀態的不足,讓服務器知道來的人是「誰」;可是Cookie以文本的形式保存在本地,自身安全性較差;因此咱們就經過Cookie識別不一樣的用戶,對應的在Session裏保存私密的信息以及超過4096字節的文本。

另外,上述所說的Cookie和Session實際上是共通性的東西,不限於語言和框架。

Django中Session相關方法

# 獲取、設置、刪除Session中數據
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在則不設置
del request.session['k1']


# 全部 鍵、值、鍵值對
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()

# 會話session的key
request.session.session_key

# 將全部Session失效日期小於當前日期的數據刪除
request.session.clear_expired()

# 檢查會話session的key在數據庫中是否存在
request.session.exists("session_key")

# 刪除當前會話的全部Session數據
request.session.delete()
  
# 刪除當前的會話數據並刪除會話的Cookie。
request.session.flush() 
    這用於確保前面的會話數據不能夠再次被用戶的瀏覽器訪問
    例如,django.contrib.auth.logout() 函數中就會調用它。

# 設置會話Session和Cookie的超時時間
request.session.set_expiry(value)
    * 若是value是個整數,session會在些秒數後失效。
    * 若是value是個datatime或timedelta,session就會在這個時間後失效。
    * 若是value是0,用戶關閉瀏覽器session就會失效。
    * 若是value是None,session會依賴全局session失效策略。

Session流程解析

 

Session版登錄驗證

from functools import wraps


def check_login(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        if request.session.get("user"):
            return func(request, *args, **kwargs)
        else:
            return redirect("/login/?next={}".format(next_url))
    return inner


def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        if user == "alex" and pwd == "alex1234":
            # 設置session
            request.session["user"] = user
            # 獲取跳到登錄頁面以前的URL
            next_url = request.GET.get("next")
            # 若是有,就跳轉回登錄以前的URL
            if next_url:
                return redirect(next_url)
            # 不然默認跳轉到index頁面
            else:
                return redirect("/index/")
    return render(request, "login.html")


@check_login
def logout(request):
    # 刪除全部當前請求相關的session
    request.session.delete()
    return redirect("/login/")


@check_login
def index(request):
    current_user = request.session.get("user", None)
    return render(request, "index.html", {"user": current_user})

Django中的Session配置

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

1. 數據庫Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默認)

2. 緩存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default'                            # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置

3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
SESSION_FILE_PATH = None                                    # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() 

4. 緩存+數據庫
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

其餘公用設置項:
SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路徑(默認)
SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默認)
SESSION_COOKIE_SECURE = False                            # 是否Https傳輸cookie(默認)
SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http傳輸(默認)
SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默認)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否關閉瀏覽器使得Session過時(默認)
SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次請求都保存Session,默認修改以後才保存(默認)

3、CBV加裝飾器

 CBV實現的登陸視圖

 
 
path('book_list/', views.BookList.as_view(),name='book_list'),

from django.views import View

from django.utils.decorators import method_decorator
class LoginView(View):

    def get(self, request):
        """
        處理GET請求
        """
        return render(request, 'login.html')

    def post(self, request):
        """
        處理POST請求 
        """
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user == 'alex' and pwd == "alex1234":
            next_url = request.GET.get("next")
            # 生成隨機字符串
            # 寫瀏覽器cookie -> session_id: 隨機字符串
            # 寫到服務端session:
            # {
            #     "隨機字符串": {'user':'alex'}
            # }
            request.session['user'] = user
            if next_url:
                return redirect(next_url)
            else:
                return redirect('/index/')
        return render(request, 'login.html')

要在CBV視圖中使用咱們上面的check_login裝飾器,有如下三種方式:

from django.utils.decorators import method_decorator

1. 加在CBV視圖的get或post方法上

from django.utils.decorators import method_decorator


class HomeView(View):

    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")
    
    @method_decorator(check_login)
    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

2. 加在dispatch方法上

from django.utils.decorators import method_decorator


class HomeView(View):

    @method_decorator(check_login)
    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

由於CBV中首先執行的就是dispatch方法,因此這麼寫至關於給get和post方法都加上了登陸校驗。

3. 直接加在視圖類上,但method_decorator必須傳 name 關鍵字參數

若是get方法和post方法都須要登陸校驗的話就寫兩個裝飾器。

from django.utils.decorators import method_decorator

@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):

    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

補充

CSRF Token相關裝飾器在CBV只能加到dispatch方法上

備註:

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


class HomeView(View):

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

4、分頁

1.自定義分頁

data = []

for i in range(1, 302):
    tmp = {"id": i, "name": "alex-{}".format(i)}
    data.append(tmp)

print(data)


def user_list(request):

    # user_list = data[0:10]
    # user_list = data[10:20]
    try:
        current_page = int(request.GET.get("page"))
    except Exception as e:
        current_page = 1

    per_page = 10

    # 數據總條數
    total_count = len(data)
    # 總頁碼
    total_page, more = divmod(total_count, per_page)
    if more:
        total_page += 1

    # 頁面最多顯示多少個頁碼
    max_show = 11
    half_show = int((max_show-1)/2)

    if current_page <= half_show:
        show_start = 1
        show_end = max_show
    else:
        if current_page + half_show >= total_page:
            show_start = total_page - max_show
            show_end = total_page
        else:
            show_start = current_page - half_show
            show_end = current_page + half_show

    # 數據庫中獲取數據
    data_start = (current_page - 1) * per_page
    data_end = current_page * per_page

    user_list = data[data_start:data_end]

    # 生成頁面上顯示的頁碼
    page_html_list = []
    # 加首頁
    first_li = '<li><a href="/user_list/?page=1">首頁</a></li>'
    page_html_list.append(first_li)
    # 加上一頁
    if current_page == 1:
        prev_li = '<li><a href="#">上一頁</a></li>'
    else:
        prev_li = '<li><a href="/user_list/?page={}">上一頁</a></li>'.format(current_page - 1)
    page_html_list.append(prev_li)
    for i in range(show_start, show_end+1):
        if i == current_page:
            li_tag = '<li class="active"><a href="/user_list/?page={0}">{0}</a></li>'.format(i)
        else:
            li_tag = '<li><a href="/user_list/?page={0}">{0}</a></li>'.format(i)
        page_html_list.append(li_tag)

    # 加下一頁
    if current_page == total_page:
        next_li = '<li><a href="#">下一頁</a></li>'
    else:
        next_li = '<li><a href="/user_list/?page={}">下一頁</a></li>'.format(current_page+1)
    page_html_list.append(next_li)

    # 加尾頁
    page_end_li = '<li><a href="/user_list/?page={}">尾頁</a></li>'.format(total_page)
    page_html_list.append(page_end_li)

    page_html = "".join(page_html_list)

    return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})
class Pagination(object):
    def __init__(self, current_page, total_count, base_url, per_page=10, max_show=11):
        """
        :param current_page: 當前頁
        :param total_count: 數據庫中數據總數
        :param per_page: 每頁顯示多少條數據
        :param max_show: 最多顯示多少頁
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        self.current_page = current_page
        self.total_count = total_count
        self.base_url = base_url
        self.per_page = per_page
        self.max_show = max_show

        # 總頁碼
        total_page, more = divmod(total_count, per_page)
        if more:
            total_page += 1
        
        half_show = int((max_show - 1) / 2)
        self.half_show = half_show
        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

    def page_html(self):

        if self.current_page <= self.half_show:
            show_start = 1
            show_end = self.max_show
        else:
            if self.current_page + self.half_show >= self.total_page:
                show_start = self.total_page - self.max_show
                show_end = self.total_page
            else:
                show_start = self.current_page - self.half_show
                show_end = self.current_page + self.half_show

                # 生成頁面上顯示的頁碼
        page_html_list = []
        # 加首頁
        first_li = '<li><a href="{}?page=1">首頁</a></li>'.format(self.base_url)
        page_html_list.append(first_li)
        # 加上一頁
        if self.current_page == 1:
            prev_li = '<li><a href="#">上一頁</a></li>'
        else:
            prev_li = '<li><a href="{0}?page={1}">上一頁</a></li>'.format(self.base_url, self.current_page - 1)
        page_html_list.append(prev_li)
        for i in range(show_start, show_end + 1):
            if i == self.current_page:
                li_tag = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
            else:
                li_tag = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
            page_html_list.append(li_tag)

        # 加下一頁
        if self.current_page == self.total_page:
            next_li = '<li><a href="#">下一頁</a></li>'
        else:
            next_li = '<li><a href="{0}?page={1}">下一頁</a></li>'.format(self.base_url, self.current_page + 1)
        page_html_list.append(next_li)

        # 加尾頁
        page_end_li = '<li><a href="{0}?page={1}">尾頁</a></li>'.format(self.base_url, self.total_page)
        page_html_list.append(page_end_li)

        return "".join(page_html_list)
def user_list(request):
    pager = Pagination(request.GET.get("page"), len(data), request.path_info)
    user_list = data[pager.start:pager.end]
    page_html = pager.page_html()
    return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})

2.Django內置分頁

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})
<!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>

5、示例

       

 

BMS settings.py

"""
Django settings for BMS project.

Generated by 'django-admin startproject' using Django 2.0.1.

For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'nk!!3wd)(-d!@0(^3+xr_2+1xucs01mj5m$lw%t0z@^c*@_#an'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
]

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',
]

ROOT_URLCONF = 'BMS.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'BMS.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'bms69',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'USER':'root',
        'PASSWORD':'123',
    }
}



# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')
]

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}
settings

BMS urls.py

"""BMS URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,re_path

from app01 import views

urlpatterns = [
    re_path(r"^login/",views.login,name='login'),
    re_path(r"^logout/",views.logout,name='logout'),
    re_path(r'^publisher_list/',views.publisher_list,name='publisher_list'),
    re_path(r'^delete_publisher/',views.delete_publisher,name='delete_publisher'),
    re_path(r'^home/',views.home,name="home"),
    # re_path(r'^book_list/',views.book_list,name="book_list"),
    re_path(r'^book_list/',views.BookList.as_view(),name="book_list"),
    # 類視圖 要調用as_view()

    # 以ip和端口後面什麼都沒有,就能匹配上url
    re_path(r'^$',views.publisher_list),
]
urls

BMS __init__.py

import pymysql
pymysql.install_as_MySQLdb()
init

app01 models.py

from django.db import models


# 出版社類
class Publisher(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name


# 書類
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    # 書的價格
    price = models.DecimalField(max_digits=8, decimal_places=2)  # 999999.99
    # 出版日期
    publish_date = models.DateTimeField(auto_now=True)  # datetime.date()
    # 書只能關聯一個出版社, 外鍵一般建在多的那一邊
    publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE)

    def __str__(self):
        return self.title


# 做者類
class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    # 多對多, 建在哪邊均可以
    books = models.ManyToManyField(to="Book", related_name="authors")  # 多對多關聯

    detail = models.OneToOneField(to="AuthorDetail", null=True,on_delete=models.CASCADE)  # 做者詳情數據的id在這張表是惟一的

    def __str__(self):
        return self.name


# 做者詳情
class AuthorDetail(models.Model):
    age = models.IntegerField()
    addr = models.TextField()


# python manage.py makemigrations
# python manage.py migrate
#
# 在項目的bms __init__ 下設置
# import pymysql
# pymysql.install_as_MySQLdb()
models

app01 views.py

from django.shortcuts import render,redirect,HttpResponse
from django.urls import reverse

from app01.models import *

# 判斷用戶有沒有登陸得裝飾器 ,
def check_login(func):
    def inner(request,*args,**kwargs):
        # 把當前訪問得網址拿到
        url = request.get_full_path()

        # login_user = request.COOKIES.get('login', None)
        # login_user = request.get_signed_cookie('login',default=None,salt='hehe')

        login_status = request.session.get('login')
        login_user = request.session.get('user')
        if login_status == '1':  # 登陸成功
            print('驗證經過'.center(120,'*'))
            return func(request,*args,**kwargs)  # 執行被裝飾得函數
        else:
            print('驗證失敗'.center(120, '*'))
            return redirect('/login/?next={}'.format(url))
    return inner


# 登陸
# def login(request):
#     # /login/?next=/book_list/
#     # /login/?next=/publisher_list/
#     if request.method == 'POST':
#         next_url = request.GET.get('next')
#
#         username = request.POST.get('user')
#         password = request.POST.get('pwd')
#
#         if username == 'alex' and password == '123':
#             # 登陸成功,跳轉到首頁
#             # 給用戶生成一個字符串,讓它保存在裏遊覽器上(這個字符串就是Cookie)
#             rep = redirect(next_url)
#             # 生成字符串 而且隨着響應返回給瀏覽器
#
#             # rep.set_cookie("login",'alex')
#             rep.set_signed_cookie("login",'alex',salt='hehe',max_age = 7)
#             # 7s 以後失效 加密過得cookie
#
#             print('====',rep)
#             # <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/home/">
#             return rep
#
#     return render(request,'login.html')


# session版登陸
def login(request):
    if request.method == 'POST':
        next_url = request.GET.get('next')

        username = request.POST.get('user')
        password = request.POST.get('pwd')

        if username == 'alex' and password == '123':
            # 利用session 保存一個login=alex
            request.session['user'] = 'alex'
            request.session['login'] = '1'
            request.session.set_expiry(86400)
            # 7s 以後失效 設置瀏覽器失效時間
            rep = redirect(next_url)
            return rep

    return render(request,'login.html')

def logout(request):
    # 把當前用戶得session 都清掉
    request.session.delete()
    return redirect('/login')


# 首頁
def home(request):
    return render(request,'home.html')


# 出版社列表
@check_login
def publisher_list(request):

    # # 判斷用戶有沒有 登陸
    # # 實際上就是判斷請求得cookie中有沒有login 1
    # print(request.COOKIES)
    # # {'csrftoken': 'NtrDhwNbXcnTSqmxa7wITT1UqccZYu2Z8ywHdf2rYhyURwdtaOAf702tsLkVfqD7', 'login': '1'}
    #
    #
    # if login_user == 'alex': # 登陸成功
    #     publisher_list = Publisher.objects.all()
    #     return render(request,'publisher_list.html',{'publisher_list':publisher_list,'user':login_user})
    # else:
    #     return redirect(reverse('login'))

    # 查詢出全部數據

    # data = Publisher.objects.all()
    # # 這裏斌不會查詢數據庫,在對data 操做時,纔會查詢數據庫 data[3:10]
    # # 總共須要多少頁
    # # 每頁顯示10條
    # per_page = 10
    # data_num = data.count()  # 數據得總數
    # # page_num,more = divmod(data_num,per_page)
    # # if more:
    # #     page_num += 1
    # current_page = request.GET.get('page',1)
    #
    # # try:
    # #     current_page = int(current_page)
    # # except Exception as e:
    # #     current_page = 1
    # # if current_page <= 0:    # 若是頁面數是  負數
    # #     current_page = 1
    # # elif current_page > page_num:   # 若是頁面 大於 總頁面
    # #     current_page = page_num
    #
    # # 頁面最多顯示11個頁面 , 當前頁數 左 + 5   右 + 5
    # max_show = 7
    # # half_show = max_show//2
    # # # 頁面最左邊顯示多少
    # # if current_page - half_show <= 1:
    # #     page_start = 1
    # #     page_end = max_show
    # # elif current_page + half_show >= page_num:  # 若是右邊 越界了
    # #     page_start = page_num - max_show + 1
    # #     page_end = page_num
    # # else:
    # #     page_start = current_page - half_show
    # #     page_end = current_page + half_show

    # from utils import mypage
    # obj = mypage.Pagination(data_num,current_page)

    # 當前頁是第3頁  (3-1)*10  - 3*10
    # date_start = (current_page-1) * per_page   # 數據從哪開始切
    # data_end = current_page * per_page         # 數據切到哪

    # publisher_list = Publisher.objects.all()
    # publisher_list = Publisher.objects.all()[20:30]
    # publisher_list = data[obj.start:obj.end]

    # # 生成頁碼
    # li = []
    # # 加一個首頁
    # li.append('<li><a href="/publisher_list/?page=1">首頁</a></li>')
    # # 加一個上一頁
    # if current_page == 1:
    #     li.append('<li class="disabled"><a href="/publisher_list/?page={0}"><span aria-hidden="true">&laquo;</span></a></li>'.format(
    #         current_page))
    # else:
    #     li.append('<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">&laquo;</span></a></li>'.format(
    #         current_page - 1))
    # for i in range(page_start,page_end+1):
    #     if i == current_page:
    #         tmp = '<li class="active"><a href="/publisher_list/?page={0}">{0}</a></li>'.format(i)
    #     else:
    #         tmp = '<li><a href="/publisher_list/?page={0}">{0}</a></li>'.format(i)
    #     li.append(tmp)
    # # 加一個下一頁
    # if current_page == page_num:
    #     li.append('<li class="disabled"><a href="/publisher_list/?page={0}"><span aria-hidden="true">&raquo;</span></a></li>'.format(
    #         current_page))
    # else:
    #     li.append('<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">&raquo;</span></a></li>'.format(
    #         current_page + 1))
    # li.append('<li><a href="/publisher_list/?page={0}">尾頁</a></li>'.format(page_num))
    # page_html = "".join(li)

    data = Publisher.objects.all()
    data_num = data.count()  # 數據得總數
    current_page = request.GET.get('page', 1)
    from utils import mypage
    obj = mypage.Pagination(data_num,current_page,request.path)
    publisher_list = data[obj.start:obj.end]
    page_html = obj.page_html()
    return render(  
        request,
        'publisher_list.html',
        {'publisher_list': publisher_list,'page_html':page_html}
    )

# # 書籍列表頁
# @check_login
# def book_list(request):
#     return render(request,'book_list.html')


# FBV(function base views) 就是在視圖裏使用函數處理請求。

# CBV版書籍列表
# CBV(class base views)就是在視圖裏使用類處理請求。

from django.views import View
# 導入django 提供得工具 把函數裝飾器變成方法裝飾器
from django.utils.decorators import method_decorator

'''三個地方可加裝飾器'''

#
# # @method_decorator(check_login,name='get')
# class BookList(View):
#     # @method_decorator(check_login)
#     # def dispatch(self, request, *args, **kwargs):
#     #     super(BookList, self).dispatch(request,*args,**kwargs)
#
#     @method_decorator(check_login)
#     def get(self,request):
#         current_page = request.GET.get('page',1)
#         data = Book.objects.all()
#         from utils import mypage
#         obj = mypage.Pagination(data.count(),current_page,request.path)
#
#         book_list = data[obj.start:obj.end]
#         page_html = obj.page_html()
#         return render(request,'book_list.html',{'book_list':book_list,'page_html':page_html})
#

# 使用django 內置得分頁

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

class BookList(View):

    @method_decorator(check_login)
    def get(self,request):
        current_page = request.GET.get('page',1)
        data = Book.objects.all()

        # 用內置得分頁類 獲得一個分頁對象
        page_obj = Paginator(data,10)
        try:
            # 嘗試去取 current_page
            ret = page_obj.page(current_page)
        except PageNotAnInteger:
            ret = page_obj.page(1)  # 返回第一頁
        except EmptyPage:
            ret = page_obj.page(page_obj.num_pages)  # 返回最後一頁

        return render(request,'book_list2.html',{'book_list':ret,})



def  delete_publisher(request):
    delete_id = request.POST.get('publisher_id')
    try:
        Publisher.objects.filter(id = delete_id).delete()
        ret = {'status':0}
    except Exception as e:
        ret = {'status':1,"msg":'刪除失敗'}

    import json
    json_ret = json.dumps(ret)
    return HttpResponse(json_ret)
views

app01 tests.py

from django.test import TestCase

from functools import wraps

#
# def my_decorator(func):
#     def wrapper(*args, **kwargs):
#         '''''decorator'''
#         print('Calling decorated function...')
#         return func(*args, **kwargs)
#
#     return wrapper
#
# @my_decorator
# def example():
#     """Docstring"""
#     print('Called example function')
#
#
# print(example.__name__, example.__doc__)
# # wrapper ''decorator

# coding=utf-8
# -*- coding=utf-8 -*-
# from functools import wraps
#
#
# def my_decorator(func):
#     @wraps(func)
#     def wrapper(*args, **kwargs):
#         '''''decorator'''
#         print('Calling decorated function...')
#         return func(*args, **kwargs)
#
#     return wrapper
#
#
# @my_decorator
# def example():
#     """Docstring"""
#     print('Called example function')
#
#
# print(example.__name__, example.__doc__)
# example Docstring
tests

templates book_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>book_list</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>
<h1>這是書籍列表頁</h1>
<a href="/logout">註銷</a>

<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>#</th>
            <th>ID</th>
            <th>書籍名稱</th>
        </tr>
        </thead>
        <tbody>
        {% for book in book_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ book.id }}</td>
                <td>{{ book.title }}</td>
            </tr>
        {% endfor %}

        </tbody>
    </table>
    <nav aria-label="...">
        <ul class="pagination">
            {{ page_html|safe }}
         </ul>
    </nav>
</div>

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
book_list

templates book_list2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>book_list</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>
<h1>這是書籍列表頁</h1>
<a href="/logout">註銷</a>

<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>#</th>
            <th>ID</th>
            <th>書籍名稱</th>
        </tr>
        </thead>
        <tbody>
        {% for book in book_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ book.id }}</td>
                <td>{{ book.title }}</td>
            </tr>
        {% endfor %}

        </tbody>
    </table>
    <nav aria-label="...">
        <ul class="pagination">
            {% if book_list.has_previous %}
                <li><a href="/book_list?page={{ book_list.previous_page_number }}">«</a></li>
            {% else %}
                 <li class="disabled"><a href="#">«</a></li>
            {% endif %}
            <li class="active"><a href="/book_list?page={{ book_list.number }}">{{ book_list.number }}</a></li>
            {% if book_list.has_next %}
                <li><a href="/book_list?page={{ book_list.next_page_number}}">»</a></li>
            {% else %}
                 <li class="disabled"><a href="#">»</a></li>
            {% endif %}
         </ul>
    </nav>
</div>

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
book_list2

templates home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home</title>
</head>
<body>
<h1>這是home頁面!!!</h1>
</body>
</html>
home

templates login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
{# action 爲空 表示往當前url 提交  #}
{#<form action="" method="post">#}
<form action="{{ request.get_full_path }}" method="post">
    {% csrf_token %}
    <input type="text" name="user">
    <input type="password" name="pwd">
    <input type="submit" value="登陸">
</form>
</body>
</html>
login

templates publisher_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>publisher_list</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/plugins/sweetalert/sweetalert.css">
    <style type="text/css">
        .sweet-alert h2{padding-top: 20px;}
    </style>
</head>
<body>
<a href="/logout">註銷</a>
<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>#</th>
            <th>ID</th>
            <th>出版社名稱</th>
            <th>操做</th>
        </tr>
        </thead>
        <tbody>
        {% for publisher in publisher_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ publisher.id }}</td>
                <td>{{ publisher.name }}</td>
                <td>
                    {#  https://github.com/lipis/bootstrap-sweetalert        #}
                    <button class="btn btn-danger delete">刪除</button>
                </td>
            </tr>
        {% endfor %}

        </tbody>
    </table>
    <nav aria-label="...">
        <ul class="pagination">
            {{ page_html|safe }}
         </ul>
    </nav>
</div>



<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/init_ajax.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
<script src="/static/plugins/sweetalert/sweetalert.min.js"></script>

<script type="text/javascript">
    //給刪除按鈕綁定事件
    $('.delete').click(function () {
        var id = $(this).parent().prev().prev().text();
        var $currentTr = $(this).parent().parent();
            swal({
              title: "肯定要刪除嗎? ",
              text: "刪了就找不回來了",
              type: "warning",
              showCancelButton: true,  // 顯不顯示取消按鈕
              confirmButtonClass: "btn-danger",
              confirmButtonText: "是,就是刪除",  //取消按鈕上的文字
              closeOnConfirm: false
            },
            function(){
                $.ajax({
                        url:'/delete_publisher/',
                        type:'post',
                        data:{'publisher_id':id},
                        success:function (arg) {
                            var ret = JSON.parse(arg);
                            if(ret.status === 0){
                                $currentTr.remove();
                                swal("刪除成功!", "你能夠跑路了", "success");
                            }else{
                                swal(ret.msg, "你能夠嘗試在刪一次", "error");
                            }
                        }
                });
            });
    });

</script>

</body>
</html>

{# 下載 dist css js 引入 #}
{# https://github.com/lipis/bootstrap-sweetalert  #}
{#   https://lipis.github.io/bootstrap-sweetalert/  #}
publisher_list

utils mypage.py

'''
自定義分頁組件

'''
class Pagination(object):

    def __init__(self, data_num, current_page,url_prefix, per_page = 10, max_show = 11):
        """
        進行初始化
        :param data_num:  數據總數
        :param current_page: 當前頁
        :param url_prefix: 生成得頁碼得連接前綴
        :param per_page: 每頁顯示多少條數據
        :param max_show: 頁面最多顯示多少個頁碼
        """
        self.data_num = data_num
        self.per_page = per_page
        self.max_show = max_show
        self.url_prefix = url_prefix

        # 把頁碼數算出來
        self.page_num, more = divmod(self.data_num, self.per_page)
        if more:
            self.page_num += 1

        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1
        if current_page <= 0:  # 若是頁面數是  負數
            current_page = 1
        elif current_page > self.page_num:  # 若是頁面 大於 總頁面
            current_page = self.page_num
        self.current_page = current_page

        # 頁碼數得一半
        self.half_show = self.max_show // 2

        if self.current_page - self.half_show <= 1:
            self.page_start = 1
            self.page_end = self.max_show
        elif self.current_page + self.half_show >= self.page_num:  # 若是右邊 越界了
            self.page_start = self.page_num - self.max_show + 1
            self.page_end = self.page_num
        else:
            self.page_start = self.current_page - self.half_show
            self.page_end = self.current_page + self.half_show

    @property
    def start(self):
        return (self.current_page-1) * self.per_page   # 數據從哪開始切

    @property
    def end(self):
        return self.current_page * self.per_page  # 數據切到哪

    def page_html(self):
        # 生成頁碼
        li = []
        # 加一個首頁
        li.append('<li><a href="{}?page=1">首頁</a></li>'.format(self.url_prefix))
        # 加一個上一頁
        if self.current_page == 1:
            li.append(
                '<li class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>')
        else:
            li.append('<li><a href="{0}?page={1}"><span aria-hidden="true">&laquo;</span></a></li>'.format(
                self.url_prefix,self.current_page - 1))
        for i in range(self.page_start, self.page_end + 1):
            if i == self.current_page:
                tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix,i)
            else:
                tmp = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix,i)
            li.append(tmp)
        # 加一個下一頁
        if self.current_page == self.page_num:
            li.append(
                '<li class="disabled"><a href="#"><span aria-hidden="true">&raquo;</span></a></li>')
        else:
            li.append('<li><a href="{0}?page={1}"><span aria-hidden="true">&raquo;</span></a></li>'.format(self.url_prefix,
                self.current_page + 1))
        li.append('<li><a href="{0}?page={1}">尾頁</a></li>'.format(self.url_prefix,self.page_num))

        return "".join(li)
mypage

myscript.py

# -*- coding:utf-8 -*-
import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()

    # 建立300個出版社
    from app01 import models

    # Publisher.objects.create(name='水星第{}出版社'.format(i))

    # obj = Publisher(name='火星出版社')
    # obj.save()

    # ret = []
    # for i in range(300):
    #     obj = Publisher(name='水星第{}出版社'.format(i))
    #     ret.append(obj)

    # ret = [models.Publisher(name='水星第{}出版社'.format(i)) for i in range(300)]

    # 批量建立300個出版社對象
    # models.Publisher.objects.bulk_create(ret)  # 只提交一次


    # 建立300本書
    import random
    ret = [models.Book(title='番茄物語{}'.format(i),price=random.randint(10, 90),publisher_id=1) for i in range(300)]
    models.Book.objects.bulk_create(ret)
myscript

 

https://github.com/alice-bj/BMS

 

6、線上 - Django分頁器

view

from django.shortcuts import render,HttpResponse

# Create your views here.
from app01.models import *
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def index(request):

    '''
    批量導入數據:

    Booklist=[]
    for i in range(100):
        Booklist.append(Book(title="book"+str(i),price=30+i*i))
    Book.objects.bulk_create(Booklist)
    '''

    '''
分頁器的使用:

    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)

    print("count:",paginator.count)           #數據總數
    print("num_pages",paginator.num_pages)    #總頁數
    print("page_range",paginator.page_range)  #頁碼的列表



    page1=paginator.page(1) #第1頁的page對象
    for i in page1:         #遍歷第1頁的全部數據對象
        print(i)

    print(page1.object_list) #第1頁的全部數據


    page2=paginator.page(2)

    print(page2.has_next())            #是否有下一頁
    print(page2.next_page_number())    #下一頁的頁碼
    print(page2.has_previous())        #是否有上一頁
    print(page2.previous_page_number()) #上一頁的頁碼



    # 拋錯
    #page=paginator.page(12)   # error:EmptyPage

    #page=paginator.page("z")   # error:PageNotAnInteger

    '''


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)
    page = request.GET.get('page',1)
    currentPage=int(page)


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" 
    integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>

<div class="container">

    <h4>分頁器</h4>
    <ul>

        {% for book in book_list %}
             <li>{{ book.title }} -----{{ book.price }}</li>
        {% endfor %}

     </ul>


    <ul class="pagination" id="pager">

                 {% if book_list.has_previous %}
                    <li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一頁</a></li>
                 {% else %}
                    <li class="previous disabled"><a href="#">上一頁</a></li>
                 {% endif %}


                 {% for num in paginator.page_range %}

                     {% if num == currentPage %}
                       <li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>
                     {% else %}
                       <li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>

                     {% endif %}
                 {% endfor %}



                 {% if book_list.has_next %}
                    <li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一頁</a></li>
                 {% else %}
                    <li class="next disabled"><a href="#">下一頁</a></li>
                 {% endif %}

            </ul>
</div>



</body>
</html>
index
def index(request):


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 15)
    page = request.GET.get('page',1)
    currentPage=int(page)

    #  若是頁數十分多時,換另一種顯示方式
    if paginator.num_pages>11:

        if currentPage-5<1:
            pageRange=range(1,11)
        elif currentPage+5>paginator.num_pages:
            pageRange=range(currentPage-5,paginator.num_pages+1)

        else:
            pageRange=range(currentPage-5,currentPage+5)

    else:
        pageRange=paginator.page_range


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",locals())
index

 

示例:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

</head>
<body>
<ul>
    {% for book in current_page %}
        <li>{{ book.title }} - {{ book.price }}</li>
    {% endfor %}

</ul>

<nav aria-label="Page navigation">
    <ul class="pagination">
        <li><a href="?page=1">首頁</a></li>
        {% if current_page.has_previous %}
            <li>
                <a href="?page={{ current_page.previous_page_number }}" aria-label="Previous">
                    <span aria-hidden="true">上一頁</span>
                </a>
            </li>
        {% else %}
            <li class="disabled">
                <a href="" aria-label="Previous">
                    <span aria-hidden="true">上一頁</span>
                </a>
            </li>
        {% endif %}

        {% for item in page_range %}
            {% if current_page_num == item %}
                <li class="active"><a href="?page={{ item }}">{{ item }}</a></li>
            {% else %}
                <li><a href="?page={{ item }}">{{ item }}</a></li>
            {% endif %}
        {% endfor %}

        {% if current_page.has_next %}
            <li>
                <a href="?page={{ current_page.next_page_number }}" aria-label="Next">
                    <span aria-hidden="true">下一頁</span>
                </a>
            </li>
        {% else %}
            <li class="disabled">
                <a href="" aria-label="Next">
                    <span aria-hidden="true">下一頁</span>
                </a>
            </li>
        {% endif %}
        <li><a href="?page={{ paginator.num_pages }}">尾頁</a></li>

    </ul>
</nav>

</body>
</html>

views.py

from django.shortcuts import render,HttpResponse

# Create your views here.

from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
from app01.models import Book

def index(request):
    '''
    批量導入
    book_list = []
    for i in range(100):
        book = Book(title='book_%s'%i,price=i*i)  # 單條插入
        book_list.append(book)
    Book.objects.bulk_create(book_list)
    '''
    book_list = Book.objects.all()

    paginator = Paginator(book_list,6)  # 20顯示20個數據
    print(paginator.count)      # 數據總數  100
    print(paginator.num_pages)  # 總頁數   13
    print(paginator.page_range) # 頁碼的列表 range(1,14)

    current_page_num = int(request.GET.get('page', 1))

    show_page = 7
    half_show_page = int(show_page/2)
    if paginator.num_pages > show_page:  # 11 表示顯示11個頁碼
        if current_page_num - half_show_page < 1:
            page_range = range(1,show_page+1)
        elif current_page_num + half_show_page > paginator.num_pages:
            page_range = range(paginator.num_pages-show_page+1,paginator.num_pages+1)
        else:
            page_range = range(current_page_num-half_show_page,current_page_num+half_show_page+1)
    else:
        page_range = paginator.page_range


    try:
        # 顯示某一頁具體數據
        current_page = paginator.page(current_page_num)
        print(current_page.object_list)

        for i in current_page:
            print(i)
    except EmptyPage as e:
        current_page = paginator.page(paginator.num_pages)
    except PageNotAnInteger as e:
        current_page = paginator.page(1)


    return render(request,'index.html',locals())

'''
http://www.cnblogs.com/yuanchenqi/articles/9036515.html
批量插入
   
    Booklist=[]
    for i in range(100):
        Booklist.append(Book(title="book"+str(i),price=30+i*i))
    Book.objects.bulk_create(Booklist)
    
分頁器:
    paginator = Paginator(book_list, 10)

    print("count:",paginator.count)           #數據總數
    print("num_pages",paginator.num_pages)    #總頁數
    print("page_range",paginator.page_range)  #頁碼的列表        

    page1=paginator.page(1) #第1頁的page對象
    for i in page1:         #遍歷第1頁的全部數據對象
        print(i)

    print(page1.object_list) #第1頁的全部數據

    page2=paginator.page(2)

    print(page2.has_next())            #是否有下一頁
    print(page2.next_page_number())    #下一頁的頁碼
    print(page2.has_previous())        #是否有上一頁
    print(page2.previous_page_number()) #上一頁的頁碼
    
    
    # 拋錯
    #page=paginator.page(12)   # error:EmptyPage

    #page=paginator.page("z")   # error:PageNotAnInteger
    
'''

models.py

from django.db import models

# Create your models here.

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)

urls.py

from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
]

7、線上 - cookie session

線上 Cookie session
http://www.cnblogs.com/yuanchenqi/articles/9036467.html

Cookie : 一個瀏覽器 針對 一個服務器 存儲得 key value 值!
在瀏覽器端得磁盤上存儲
默認時間是2周,可設置失效時間! 就算關機開機,cookie任然存在!!


設置Cookie 用響應體 利用cookie 維持會話得記錄保存狀態!
response = HttpResponse('登陸成功')

HttpResponse() render() redirect() 三個response 均可設置cookie

# 1. 設置失效時間
response.set_cookie('is_login', True, max_age = 15) # 時間 15s 後

import datetime # 固定在哪一個時刻 過時
date = datetime.datetime(year=2018,month=5,day=29,hour=14,minute=32,seconds=10)
response.set_cookie('username',username,expires=date)

# 2. 有效路徑
response.set_cookie('username',username,path='/index/')

# 3. 清cookie 瀏覽器
ctrl + shift + delete

# 4. 設置上次訪問時間
import datetime
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
設置爲北京時間
TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'

last_time = request.COOKIE.get('last_visit_time','')
response.set_cookie('last_visit_time',now)
return render(request,'index.html',{'username':username,'last_time':last_time})

# 5.利用cookie設置 上次訪問得商品
。。。
return response


is_login = request.COOKIE.get('is_login')
if is_login:
username = request.COOKIE.get('username')
return render(request,'index.html',{'username':username})
else:
return redirect('/login/')

-------------------------------------
session:

寫:
request.session['is_login'] = True
request.session['username'] = "yuan"
import datetime
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
request.session['last_visit_time'] = now

if request.COOKIE.get('sessionid'):
在django-session表中更新一條記錄:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":'alice'}
else:
1. 生成隨機字符串
2. response.set_cookie('sessionid',2312312sadasdasdas2312)
3. 在django-session表中建立一條記錄:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":'yuan'}


讀:
request.session.get('is_login')
username = request.session.get('username')
last_visit_time = request.session.get('last_visit_time')

1. request.COOKIE.get('sessionid') # 2312312sadasdasdas2312
2. django-session表中得記錄過濾
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":'yuan'}
obj = djsngo-session.object.filter(session-key="2312312sadasdasdas2312").first()
3. obj.session-data.get('is_login')


註銷:
del request.session['is_login'] # 不建議這麼作; 要刪就要刪整條記錄
request.session.flush()

1. session_str = request.COOKIE.get('sessionid')
2. django-session.object.filter(session-key=session-str).delete()
3. response.delete_cookie('sessionid')

session 配置:
Django默認支持Session,而且默認是將Session數據存儲在數據庫中,即:django_session 表中。
配置 settings.py

SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認)

SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認)
SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時(默認)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改以後才保存(默認)


總結:
1. 寫cookie:
response.set_cookie(key,value)
2, 讀cookie:
request.COOKIE.get(key)
3. 寫session
request.session[key] = value
注意django對應得操做
if request.COOKIE.get('sessionid'):
在django-session表中更新一條記錄:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":'alice'}
else:
1. 生成隨機字符串
2. response.set_cookie('sessionid',2312312sadasdasdas2312)
3. 在django-session表中建立一條記錄:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":'yuan'}
4. 讀session:
request.session[key]
1. request.COOKIE.get('sessionid') # 2312312sadasdasdas2312
2. django-session表中得記錄過濾
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":'yuan'}
obj = djsngo-session.object.filter(session-key="2312312sadasdasdas2312").first()
3. obj.session-data.get('is_login')
5. 刪session:
request.session.flush()
1. session_str = request.COOKIE.get('sessionid')
2. django-session.object.filter(session-key=session-str).delete()
3. response.delete_cookie('sessionid')
相關文章
相關標籤/搜索