반응형

테스트 데이터를 대량으로 만들어 보겠습니다. 가장 편한 방법은 플라스크 셸을 이용하는 것입니다.

for문 안에 내용은 탭으로 무조건 들여쓰기를 해주세요. 적용 후에 exit(0) 명령으로 쉘 스크립트를 나갈 수 있습니다.

 

그리고 서버를 실행해보겠습니다.

 

데이터가 어마무시하게 들어갔습니다. 

 

그런데 보통 이렇게 안 쓰고 페이지별로 10개씩이라든가 나눠서 보여줍니다.

그걸 페이징이라고 하는데 그걸 구현해 보겠습니다.

 

from datetime import datetime

from flask import Blueprint, render_template, request, url_for
from ..models import Question
from werkzeug.utils import redirect
from .. import db

from ..forms import QuestionForm, AnswerForm

bp = Blueprint('question', __name__, url_prefix='/question')

@bp.route('/list')
def _list():
    page = request.args.get('page', type=int, default=1) # 페이지
    question_list = Question.query.order_by(Question.create_date.desc())
    question_list = question_list.paginate(page, per_page=10)
    return render_template('question/question_list.html', question_list=question_list)

@bp.route('/detail/<int:question_id>')
def detail(question_id):
    form = AnswerForm()
    question = Question.query.get_or_404(question_id)
    return render_template('question/question_detail.html', question=question, form=form)

@bp.route('/create/', methods=('GET', 'POST'))
def create():
    form = QuestionForm()
    if request.method == 'POST' and form.validate_on_submit():
        question = Question(subject=form.subject.data, content=form.content.data, create_date=datetime.now())
        db.session.add(question)
        db.session.commit()
        return redirect(url_for('main.index'))
    return render_template('question/question_form.html', form=form)

question_views.py 입니다.

 

reuqest.args.get('page', type=int, default=1)

page값이 없으면 기본값이 1이라는 의미이고 page자료형이 int형이라는 의미입니다.

( localhost:5000/question/list/?page=5 ) 이런식인 것이다. 

( localhost:5000/question/list/ ) 는 page값이 자동으로 1인 것입니다.

 

question_list.paginate(page, per_page=10)

per_page페이지마다 보여줄 게시물을 의미합니다.

paginate함수조회 데이터를 감싸 Pagination객체로 반환합니다.

question_list는 paginate 함수를 사용해 Pagination 객체가 되어서 페이징 처리를 아주 쉽게 해줍니다.

 

즉 여기서는 페이징 설정을 해주는 것입니다.

항목 설명(예시)
items 현재 페이지에 해당하는 게시물 리스트
[<Question 282>,<Question 283>...]
total 게시물 전체 개수
per_page 페이지당 보여줄 게시물 개수
page 현재 페이지 번호
iter_pages 페이지 범위 ([1, 2....31])
prev_num / next_num 이전 페이지, 다음 페이지 번호 (현재  페이지 3인 경우 2 / 4)
has_prev / has_next 이전, 다음 페이지 존재여부 (True, False)

 

페이징은 사실 구현하기 무척 어려운 기술입니다.

 

 

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    {% extends 'base.html' %}
    {% block content %}

    <div class="container my-3 text-center">
        <table calss="table" width="100%">
            <thead >
                <tr class="bg-dark text-white">
                        <th> 번호 </th>
                        <th> 제목 </th>
                        <th> 작성일시 </th>
                </tr>
            </thead>

            <tbody>
                {% if question_list %}
                {% for question in question_list.items %}
                <tr>
                        <td>{{ loop.index }}</td>
                        <td><a href="{{ url_for('question.detail', question_id=question.id) }}">{{question.subject}}</a></td>
                        <td>{{ question.create_date  }}</td>
                </tr>
                {% endfor %}
                {% else %}
                <tr>
                    <td colspan="3"> 질문이 없습니다. </td>
                </tr>
                {% endif %}
            </tbody>
        </table>
        <!-- 페이징 -->
        <nav aria-label="Page navigation example">
          <ul class="pagination pagination-sm my-5 justify-content-center">
              <!-- 이전 페이징 구현 (이전 페이지 있을시)-->
              {% if question_list.has_prev %}
                <li class="page-item">
                    <a class="page-link" href="?page={{ question_list.prev_num }}">이전</a>
                </li>
              <!-- 이전 페이지가 없을 시 -->
              {% else %}
                <li class="page-item disabled">
                    <a class="page-link" href="">이전</a>
                </li>
              {% endif %}
              <!-- 중간 페이징 -->
              {% for page_num in question_list.iter_pages() %}
                {% if page_num %}
                    {% if page_num != question_list.page %}
                        <li class="page-item">
                            <a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
                        </li>
                    {% else %}
                        <li class="page-item active" aria-current="page">
                            <a class="page-link" href="#">{{ page_num }}</a>
                        </li>
                    {% endif %}
                {% else %}
                    <li class="disabled">
                        <a class="page-link" href="#">...</a>
                    </li>
                {% endif %}
              {% endfor %}
              <!-- 다음 페이징 구현 (다음 페이지가 있는 경우_ -->
              {% if question_list.has_next %}
                  <li class="page-item">
                      <a class="page-link" href="?page={{ question_list.next_num }}">다음</a>
                  </li>
              <!-- 다음 페이지 없는 경우 -->
              {% else %}
                  <li class="page-item disabled">
                      <a class="page-link" tabindex="-1" aria-disabled="true" href="#">다음</a>
                  </li>
              {% endif %}
          </ul>
        </nav>

        </ul>
        <a href="{{ url_for('question.create') }}" class="btn btn-primary"> 질문 등록하기 </a>
    </div>

    {% endblock %}

</body>
</html>

question_list.html 입니다.

 

이전 페이징 구현하는 것인데 만약 이전 페이지가 없다면 disable로 클릭할 수 없게 만듭니다.

{% if question_list.has_prev %}

 

다음 페이징 구현하는 것도 똑같습니다.

{% if question_list.has_next %}

 

문제는 중간페이징인데

 

question_list.iter_pages()이게 기능이 좀 특이합니다. 전체 페이지를 하나씩 도는 반복자는 맞습니다.

하지만 만약 페이지가 7페이지라면 1, 2, None, 5, 6, 7, 8, 9, 10, 11, None, 30, 31 이렇게 나옵니다.

이게 페이지가 너무 많으면 None을 보여줍니다. 

그리고 우리는 None이면 ...을 출력하게 해놔서 저렇게 보이는 것입니다.

(<a class="page-link" href="#">...</a>)

 

그래서 None값이 아니고 현재 페이지와 다르면 그 페이지로 이동하는 url이 있는 페이지를 만들어줍니다.

{% if page_num != question_list.page %} 

<a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>

 

만약 현재 페이지면 저렇게 파란색으로 active 효과를 주고 url을 안 줍니다.

<li class="page-item active" aria-current="page">
    <a class="page-link" href="#">{{ page_num }}</a>
</li>

 

 

반응형