當貼文數量增長,一次載入所有資料會嚴重影響效能。本文示範如何使用 Flask-SQLAlchemy 內建的 paginate 方法,為微型部落格加入分頁導航,並套用至首頁與個人頁面。
在 forms.py 定義 PostForm,index.html 加入表單。視圖函數處理送出:
@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
@app.route('/index/<int:page>', methods=['GET', 'POST'])
@login_required
def index(page=1):
form = PostForm()
if form.validate_on_submit():
post = Post(body=form.post.data, timestamp=datetime.utcnow(), author=g.user)
db.session.add(post)
db.session.commit()
flash('Your post is now live!')
return redirect(url_for('index')) # PRG 模式避免重複送出
posts = g.user.followed_posts().paginate(page, POSTS_PER_PAGE, False)
return render_template('index.html', title='Home', form=form, posts=posts)
為何要重導向? 避免使用者重新整理頁面時瀏覽器再次送出 POST 請求,造成重複貼文。
在 config.py 設定:
POSTS_PER_PAGE = 3 # 實際部署請調大
paginate(page, per_page, error_out) 回傳 Pagination 物件,包含實用屬性:
items:當頁資料列表has_prev、has_next:是否有上/下頁prev_num、next_num:上/下頁頁碼模板 index.html 導航區塊:
{% for post in posts.items %}
{% include 'post.html' %}
{% endfor %}
{% if posts.has_prev %}
<a href="{{ url_for('index', page=posts.prev_num) }}"><< Newer posts</a>
{% else %}
<< Newer posts
{% endif %} |
{% if posts.has_next %}
<a href="{{ url_for('index', page=posts.next_num) }}">Older posts >></a>
{% else %}
Older posts >>
{% endif %}
將單篇貼文渲染邏輯抽離至 post.html,首頁與個人頁面皆可 {% include 'post.html' %},避免重複程式碼。
@app.route('/user/<nickname>')
@app.route('/user/<nickname>/<int:page>')
@login_required
def user(nickname, page=1):
user = User.query.filter_by(nickname=nickname).first()
if user is None:
flash('User ' + nickname + ' not found.')
return redirect(url_for('index'))
posts = user.posts.paginate(page, POSTS_PER_PAGE, False)
return render_template('user.html', user=user, posts=posts)
user.html 同樣使用 posts.items 迴圈與分頁導航,唯導航連結需帶入 nickname 參數。
完成以上步驟,即可支援大量貼文的高效分頁瀏覽,並保持程式碼模組化、易維護。