1. 程式人生 > >Flask快速實現分頁效果

Flask快速實現分頁效果

先上整體效果圖:

然後是分頁圖詳情:

與本例相關的路由和模板包括:

路由:views.py

@app.route('/blog/list/<int:page>', methods=['GET'])
@login_required
def blog_list(page=None):
    ...

模板:blog_list.html和pages.html

blog_list.html作為部落格頁面,pages.html模板為分頁頁面,呈現時會在blog_list.html中匯入pages.html的內容。

{%import 'pages.html' as pg%}
{{pg.my_paginage(pagination,'art_list')}}

首先從路由開始:

路由的設計思路是根據查詢的頁碼作為引數,利用FlaskSQLAlchemy的Model進行查詢並對查詢結果進行分頁處理。

@app.route('/blog/list/<int:page>', methods=['GET'])
@login_required
def blog_list(page=None):
    #每個人只能看自己發表的blog
    if not page:
        page = 1
    from models import Blog
    from models import User
    user_id = User.query.filter_by(username=session['user']).first().id
    #paginate方法返回一個sqlalchemy.Pagination型別物件
    blogs = Blog.query.filter_by(user_id=user_id).order_by(Blog.addtime.desc()).paginate(page=page,per_page=3)
    category=[(1, '情感'), (2, '星座'), (3, '愛情')]
    return render_template('blog_list.html', title='部落格列表',session=session,blogs=blogs.items,category=category,pagination=blogs)

分析一下上述程式碼:

1. @app.route裝飾器定義了路由

2. @login_required是自定義裝飾器,用來限定只有登入使用者才可以瀏覽部落格列表,未登入使用者會進入登入頁面

3. 作為Model的Blog中有一個外來鍵屬性user_id引用著使用者表,用來記錄部落格的作者資訊

4. blogs是一個FlaskSQLAlchemy中的Pagination型別物件。一個Query物件呼叫paginate方法就獲得了Pagination物件。paginate方法傳入了兩個引數,一個是當前頁,另一個是每一頁最多顯示多少部落格。paginate的返回值為代表當前頁的Pagination物件。一個Paginationi物件的常用屬性有:

  • items 當前頁面中的所有記錄(比如當前頁上有5條記錄,items就是以列表形式組織這5個記錄)
  • query 當前頁的query物件(通過query物件呼叫paginate方法獲得的Pagination物件)
  • page 當前頁碼(比如當前頁是第5頁,返回5)
  • prev_num 上一頁頁碼
  • next_num 下一頁頁碼
  • has_next 是否有下一頁 True/False
  • has_prev 是否有上一頁 True/False
  • pages 查詢得到的總頁數 per_page 每頁顯示的記錄條數
  • total 總的記錄條數

常用方法有:

  • prev() 上一頁的分頁物件Pagination
  • next() 下一頁的分頁物件Pagination
  • iter_pages(left_edge=2,left_current=2,right_current=5,right_edge=2)
  • iter_pages 用來獲得針對當前頁的應顯示的分頁頁碼列表。
  • 假設當前共有100頁,當前頁為50頁,按照預設的引數設定呼叫iter_pages獲得的列表為:
  • [1,2,None,48,49,50,51,52,53,54,55,None,99,100]

5. 渲染blog_list.html模板時,傳入渲染時需要的若干引數,比較重要的是傳入blogs引數用來讓模板顯示查詢出來的應該在本頁面中顯示的部落格資訊,另外是傳入pagination引數,利用傳入的Pagination物件的相關屬性方法動態生成分頁的相關內容。

看一下pages.html模板的內容:

{%macro my_paginate(pagination,url)%}
<nav>
    <ul class="pagination">

        {%if pagination.has_prev%}
        <li class="page-item active"><a class="page-link" href="{{url_for(url,page=pagination.page-1)}}">上一頁</a></li>
        {%else%}
        <li class="page-item disabled"><a class="page-link" href="#">上一頁</a></li>
        {%endif%}

            {%for page in pagination.iter_pages(1,1,3,1)%}
            {%if page%}
                <li class="page-item {%if page==pagination.page%}active{%endif%}"><a class="page-link" href="{{url_for(url,page=page)}}">{{page}}</a></li>
            {%else%}
                <li class="page-item disabled"><a class="page-link" href="#">&hellip;</a></li>
            {%endif%}

        {%endfor%}

        {%if pagination.has_next%}
        <li class="page-item active"><a class="page-link" href="{{url_for(url,page=pagination.page+1)}}">下一頁</a></li>
        {%else%}
        <li class="page-item disabled"><a class="page-link" href="#">下一頁</a></li>
        {%endif%}

    </ul>
</nav>
{%endmacro%}

分析一下上述頁面程式碼:、

整體來說就是根據當前對“上一頁”,“頁碼”和“下一頁”進行不同的設定

1. 使用JinJa2的巨集,定義my_paginate方法,傳入路徑和pagination物件作為引數。通過呼叫巨集的執行生成分頁內容。

2. 通過設定class為pagination,可以使用FlaskBootStrap預置CSS樣式

3. 利用JinJa2的if語句根據當前頁是否還有前一頁使用不同的元素和class。

    如果當前頁有上一頁,則pagination物件的has_prev為True,此時li標籤的class為page-item和active,採用的BootStrap樣式意      為此時上一頁是可點的。點選後跳轉的連結會是url_for函式根據傳入的路由方法名稱(也就是url引數值)並新增上page引數,引數值為當前頁碼-1

    如果當前頁沒有上一頁,則pagination物件的has_prev為False,此時li標籤的class為page-item和disable,採用的BootStrap樣      式意為此時上一頁是不可點的。跳轉的連結會是#

4. 與“上一頁”處理類似的是對“下一頁”的處理。如果當前頁有下一頁時設定樣式和點選跳轉路徑,如果沒有下一頁了,則設定為        不可點選並且跳轉路徑為#

5. 利用iter_page(1,1,3,1)會獲得基於當前頁應該顯示的頁碼列表。如上面截圖所示,如果當前頁是第4頁,獲得的分頁列表內容         就是[1,None,3,4,5,6,None,9],如果當前頁是第9頁,獲得的分頁列表內容是[1,None,8,9]

6. 利用JinJa2的for語句遍歷列表,如果是頁碼,就根據頁碼生成a標籤中的文字並設定跳轉路徑並新增上page引數。如果是None,a標籤中的文字為實體名錶示的省略號,路徑為“#”。額外的,如果遍歷時獲得了當前頁碼所對應的數字時,為li標籤的class屬性新增上額外的active以獲得額外的樣式。

最後在blog_list.html中要引入pages.html

{%import 'pages.html' as pg%}
{{pg.my_paginate(pagination,'blog_list')}}

在blog_list.html中匯入pages.html模板並呼叫pages.html中定義的my_pagination巨集,傳入兩個引數,第一個引數是pagination物件,這個引數是從views.py中渲染blog_list.html的時候傳入的,另外一個就是一個字串'blog_list',它對應的是views.py中路由方法的名稱,有了這個名稱在my_paginate中就可以利用url_for函式進行路由方法對應路徑的尋找。