Django nextpage

前天晚上心血來潮, 便把 django-nextpage 給生出來了。 其實這個 package 已經在 StreetVoice 內部用很久了, 只是一直沒時間把它包成 package 然後 release 出來。

以前都會用 django-pagination 來做分頁的功能, 非常方便快速, 只要在 template 多加幾個 tag 就可以直接產出分頁了, 像是這樣。

{% load pagination_tags %}

{% autopaginate items 20 %}
{% for item in items %}
    {{ item.name }}
{% endfor %}

<div class="pagination">  
  {% paginate %}
</div>  

然而其實每次算分頁都得做一次 SQL 的 COUNT(), 當資料多的時候就會開始變慢, 所以其實現在很多網站都只提供"下一頁"這個功能, 而不是 1, 2, … 120 頁這樣的方式, 畢竟那麼多分頁, 對於使用者來說第 2 頁, 跟 5 頁都是未知的結果, 有時候也只是亂槍打鳥亂按一個分頁, 這時候倒不如你就直接給使用者一些建議的結果, 效果反而還比較好。

所以有一些網站就只提供下一頁, 或者像是 twitter / facebook 的 timeline, 都直接給你下一頁而已, 甚至就直接叫 Load more。

只提供下一頁的好處就是不用再去 count 了, 所以原本兩次 query 變成一次, 而且通常在 django 裡, count 的 query 都比你實際要資料的 query 還慢。

所以如果不需要 count 的話, 接下來就只剩得知道"還有沒有下一頁"這件事了, 有看到人家的解法是, 一樣做兩次 query, 如果我要 20 筆資料, 那麼就多做一次抓 21 筆的 query, 如果有 21 筆的話, 那麼就代表有下一頁, hmm … 聽起來就不太好 XD

為何不一次就抓取 21 筆, 如果是大於 20 筆, 那麼就代表有下一頁啦, 所以就弄了 django-nextpage 出來, 主要概念大概像是這樣。

## params
paginate_by = 20  
page = request.GET.get('page', 1)

## code
limit = paginate_by + 1

offset = (page - 1) * limit - (page - 1)  
items = items[offset:limit + offset]

items_count = len(list(items))

items_we_actually_want = items[:limit - 1]

next_page = page + 1 if items_count == limit else None  
prev_page = page - 1 if page > 1 else None  

這樣一個 query 就解決了, 使用方法也跟 django-pagination 一樣, 可以直接把 django-pagination 換掉了阿, 你只需要把 load pagination_tags 換成 load nextpage 即可, 使用方式如下。

先用 pip 安裝

$ pip install django-nextpage`

在 INSTALLED_APPS 加上 nextpage

INSTALLED_APPS = (  
    # ...
    'nextpage',
)

最後換成 load nextpage templatetag 即可

{% load nextpage %}

{% utopaginate items 20 %}
{% for item in items %}
    {{ item.name }}
{% endfor %}

{% paginate %}

That’s all!

最後

敝公司為舉辦簡單生活節的中子文化 / StreetVoice 持續徵人中, 使用 Python/Django 一個打十個, 工作輕鬆不用加班, 又是藝文產業, 可常看到正妹, 也可秘密獲得演唱會入場卷, 有興趣嗎? 趕快來談談吧! 請來信 tzangms [at] streetvoice.com

tzangms

Read more posts by this author.

Subscribe to Oceanic / 海海人生

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!