본문 바로가기

TIL/Python

[Python] Flask 페이지네이션

 

#HTML
{% for post in posts %}
<article>
    <a href="{{ url_for('blog.detail', id=post['id'])}}">
        {{ post['title'] }}
    </a>
</article>
{% endfor %}
{{ pagination.links | safe }}

 

pagination.links

Flask-paginate에서 pagination 객체를 만들어서 넘겨주면, 객체가 갖고있는 links라는 attribute가 바로 우리가 원하는 그 각 페이지로 갈 수 있는 링크 부분입니다.

내부적으로는 우리가 구현하고싶은 html 덩어리를 추상화해놓았습니다. 만약 Flask-paginate를 사용하지 않았다면 여기가 엄청 복잡해졌겠죠. 다만, safe를 걸어주어서, 안전한 객체가 전달되었으니 브라우저 상에서 실행해도 괜찮다~ 라고 브라우저를 안심시켜줘야 html 위에 보이게 할 수 있습니다.

 

from flask_paginate import Pagination, get_page_args

@BP.route("/", methods=("GET",))  # index 페이지를 호출하면
def index():
    per_page = 10
    page, _, offset = get_page_args(per_page=per_page)  # 포스트 10개씩 페이지네이션을 하겠다.
    # 이 때 두 번째 return값은 per_page입니다.
    # 저는 per_page를 따로 get_page_args에 넣어줘서, per_page를 받아서 사용하지는 않았습니다.
    # page는 현재 위치한 page입니다. 기본적으로 1이고, 페이지 링크를 누르면 2, 3, ...입니다.
    # offset은 page에 따라 몇 번째 post부터 보여줄지입니다.
    # 기본적으로 0이고, 2페이지라면 10, 3페이지라면 20이겠죠.

    cur = get_cur()
        cur.execute("SELECT COUNT(*) FROM posts;")  # 일단 총 몇 개의 포스트가 있는지를 알아야합니다.
        total = cur.fetchone()[0]
    cur.execute(
        "SELECT * FROM posts ORDER BY created "  # SQL SELECT로 포스트를 가져오되,
        "DESC LIMIT %s OFFSET %s;",  # offset부터 per_page만큼의 포스트를 가져옵니다.
        (per_page, offset),
    )
    posts = cur.fetchall()

    return render_template(
        "blog/index.html",
        posts=posts,
        pagination=Pagination(
            page=page,  # 지금 우리가 보여줄 페이지는 1 또는 2, 3, 4, ... 페이지인데,
            total=total,  # 총 몇 개의 포스트인지를 미리 알려주고,
            per_page=per_page,  # 한 페이지당 몇 개의 포스트를 보여줄지 알려주고,
            prev_label="<<",  # 전 페이지와,
            next_label=">>",  # 후 페이지로 가는 링크의 버튼 모양을 알려주고,
            format_total=True,  # 총 몇 개의 포스트 중 몇 개의 포스트를 보여주고있는지 시각화,
        ),
        search=True,  # 페이지 검색 기능을 주고,
        bs_version=5,  # Bootstrap 사용시 이를 활용할 수 있게 버전을 알려줍니다.
    )

 

이를 요약하면 다음과 같은 단계로 진행된다.

  1. Flask에 N번째 페이지(page)를 보여달라는 요청이 들어옴
  2. N번째 페이지라면 10 * (N-1) 번째 포스트(offset)부터 보여줘야겠죠, 예를 들면 1번 페이지면 0번 포스트, 2번 페이지면 10번 포스트처럼요. 그걸 get_page_args()함수로 계산해옵니다.
  3. SQL로 DB에 있는 포스트를 가져올 때, 10 * (N-1) 번째 포스트에서부터 10개만큼 가져오도록 LIMIT와 OFFSET을 줍니다.
  4. render_template()할 때, Pagination객체를 같이 전달해서, html에서 뭘 잘 몰라도 이 객체에서 전달해준 페이지 수라거나, 기호라거나, 내장된 html 형태 등을 잘 사용하게끔 돕습니다.

 

 Flask-paginate 공식문서

 

flask-paginate 0.5.0 documentation — flask-paginate 0.5.0 documentation

Configuration If you want to show the pagination information, add below lines to your css file. .pagination-page-info { padding: .6em; padding-left: 0; width: 40em; margin: .5em; margin-left: 0; font-size: 12px; } .pagination-page-info b { color: black; ba

pythonhosted.org

 

 

@app.route('/')
def index():
    per_page = 4
    page, _, offset = get_page_args(per_page=per_page)
    conn = sqlite3.connect(DATABASE)
    cur = conn.cursor()
    cur.execute("SELECT COUNT(*) FROM posts") 
    total = cur.fetchone()[0]
    cur.execute(
        "SELECT * FROM posts ORDER BY date DESC LIMIT ? OFFSET ?;",(per_page, offset)
    )
    posts = cur.fetchall()
    if session.get("logged_in"):
        return render_template('index.html', posts=posts, logged_id=session["nickname"], pagination=Pagination(page=page,total=total,per_page=per_page,prev_label="<<",next_label=">>",format_total=True))
    
    return render_template('index.html', posts=posts, pagination=Pagination(page=page,total=total,per_page=per_page, prev_label="<<", next_label=">>", format_total=True))