이전 포스팅에서는
게시글 작성 페이지
를CreateView
를 통해 구현하는 방법을 배웠다. 본 포스팅에서는게시글 목록 페이지
를ListView
를 통해 구현하는 방법을 알아본다.
기존에 작성된 함수형 뷰는 아래와 같다. 주석처리 해준다.
#views.py
# def post_list(request):
# posts = Post.objects.all().order_by("-dt_modified") #생성일 기준 내림차순으로 변경
# page = request.GET.get("page", 1) #GET 요청 방식일 때 url에서 로컬 호스트/ 다음 page에 해당하는 값을 가져오고 값이 없다면 1을 기본값으로 함
# paginator = Paginator(posts, 9) #posts를 페이지 당 9개씩 호출
# page_obj = paginator.get_page(page) #가져온 page 값에 해당하는 페이지의 데이터를 불러온다
# context = {"page_obj": page_obj}
# return render(request, 'posts/post_list.html', context=context)
다시봐도 상당히 복잡하다.
ListView
제네릭 뷰를 상속받은 클래스를 생성한다.
#views.py
class PostListView(ListView):
model = Post
template_name = "posts/post_list.html"
context_object_name = "posts"
ordering = ["-dt_created"]
paginate_by = 9
page_kwarg = 'page'
접근할
모델
을 정의하고, 렌더할템플릿
을 정의하고, context로 전달할객체 이름
을 정의하고, 정렬 기준을오름차순
으로 정의하고, 페이지 당 표기되는게시글 수
를 정의하고, 현재 페이지를 조회하기 위해 전달하는이름
을 정의한다.
기존처럼 복잡한 구조가 아닌, 변수에 대한 값만 정해주면 훨씬 간단하게 작성할 수 있다.
ListView
를 상속받기 위해서는import
해야한다.
ListView
는context
에 각 페이지에 해당하는 데이터를 전달할 때, 데이터의를page_obj
라는키
의값
으로 전달한다.따라서
템플릿
에서는page_obj
를 통해 각 페이지에 해당하는 데이터에 접근할 수 있다.여기서
context_object_name
변수에 지정하는값(여기서는 posts)
을 통해서도 접근할 수 있다.
page_kwarg
는 현재 페이지를 어떤값
으로 조회하는지를 전달한다.이해를 위해
템플릿
의처음으로
버튼을 살펴보면<a class="able" href="?page=1"><<</a>
태그로 작성되어 있다.여기서 url을 살펴보면
?page=1
로 작성된 것을 확인할 수 있는데 이는 1번 페이지로 이동하는 것을 말한다.만약
템플릿
에 작성된page
이름이pages
로 변경되는 것과 같이page_kwarg
에 지정한 값과 다르다면, 원하는 페이지로 이동하지 못한다.
데이터에 접근하기 위한
템플릿 변수
를page_obj
또는context_object_name
에 지정한 값posts
둘 중 하나를 사용해야 하는데,<dear>
프로젝트는 이미page_obj
로 사용하고 있기 때문에 변경하지 않아도 된다.
<!--post_list.html-->
{% block content %}
<div class="btn_post">
<a href={% url "post-create" %}>기록하기</a>
</div>
{% if page_obj %}
<div class="post_container">
{% for post in page_obj.object_list %}
<div class="post"><a href="{% url "post-detail" post.id %}">
<h2 class="title">{{post.title}}</h2>
<p class="date">{{post.dt_created|date:"Y년 m월 d일 H시 i분"}}</p>
<p class="text">{{post.content}}</p>
</a></div>
{% endfor %}
</div>
<div class="pagination">
{% if page_obj.has_previous %}
<a class="able" href="?page=1"><<</a>
{% else %}
<a class="disable" onclick="return false;" href="#"><<</a>
{% endif %}
{% if page_obj.has_previous %}
<a class="able" href="?page={{ page_obj.previous_page_number }}"><</a>
{% else %}
<a class="disable" onclick="return false;" href="#"><</a>
{% endif %}
{% for page_number in page_obj.paginator.page_range %}
{% if page_number == page_obj.number %}
<a class="disable" id="current" onclick="return false;" href="#">{{ page_number }}</a>
{% elif page_obj.number <= 3 and page_number <= 5 %}
<a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
{% elif page_obj.number > page_obj.paginator.num_pages|add:-3 and page_number >= page_obj.paginator.num_pages|add:-4 %}
<a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
{% elif page_number >= page_obj.number|add:-2 and page_number <= page_obj.number|add:2 %}
<a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="able" href="?page={{ page_obj.next_page_number }}">></a>
{% else %}
<a class="disable" onclick="return false;" href="#">></a>
{% endif %}
{% if page_obj.has_next %}
<a class="able" href="?page={{ page_obj.paginator.num_pages }}">>></a>
{% else %}
<a class="disable" onclick="return false;" href="#">>></a>
{% endif %}
</div>
{% else %}
<div class="blank">
<p>
등록된 게시글이 없습니다.<br>
게시글을 등록해보세요.
</p>
</div>
{% endif %}
{% endblock content %}
url 패턴에서
post_list
를PostListView
로 변경해야 한다.
urls.py
urlpatterns = [
# path('', views.index),
path('', views.PostListView.as_view(), name="post-list"),
path('posts/new/', views.PostCreateView.as_view(), name="post-create"),
path('posts/<int:post_id>/', views.PostDetailView.as_view(), name="post-detail"),
path('posts/<int:post_id>/edit/', views.post_update, name="post-update"),
path('posts/<int:post_id>/delete/', views.post_delete, name="post-delete"),
]