Django
Chapter 5-2 📌 Django CBV - ListView로 블로그 목록 + 검색 + 페이지네이션 구현하기
Chansman
2025. 5. 8. 10:01
📌 Django CBV - ListView로 블로그 목록 + 검색 + 페이지네이션 구현하기
1️⃣ FBV와 분리된 CBV 구조 설계
기존의 views.py 와는 구분하기 위해 cb_views.py 를 새로 만들어 CBV 관련 로직을 작성합니다.
# blog/cb_views.py
from django.db.models import Q
from django.views.generic import ListView
from blog.models import Blog
class BlogListView(ListView):
queryset = Blog.objects.all()
template_name = 'blog_list.html'
paginate_by = 10
ordering = ('-created_at', )
def get_queryset(self):
queryset = super().get_queryset()
q = self.request.GET.get('q')
if q:
queryset = queryset.filter(
Q(title__icontains=q) |
Q(content__icontains=q)
)
return queryset
2️⃣ CBV URL 연결하기
# config/urls.py
from blog import cb_views
urlpatterns = [
path('cb/', cb_views.BlogListView.as_view(), name='cb_blog_list'),
]
✔️ as_view() 메서드를 호출하여 클래스 기반 뷰 인스턴스를 생성합니다.
3️⃣ 템플릿에서 object_list 활용하기
CBV에서 queryset이 렌더링될 때 기본적으로 object_list라는 이름으로 템플릿에 전달됩니다.
{# blog/blog_list.html #}
{% extends 'base.html' %}
{% block content %}
<h1>블로그 목록</h1>
<p style="text-align: right">
<a href="{% url 'blog_create' %}">생성</a>
</p>
{% for blog in object_list %}
<p>
<a href="{% url 'blog_detail' blog.pk %}">
({{ blog.id }}){{ blog.title }} - <small>{{ blog.created_at|date:"Y-m-d" }}</small>
</a>
</p>
{% endfor %}
<form method="get" style="margin-bottom: 10px;">
<input name="q" type="text" placeholder="검색어를 입력하세요." value="{{ request.GET.q }}">
<button>검색</button>
</form>
4️⃣ 기존 FBV에서도 동일한 변수명 적용
FBV에서도 object_list와 page_obj를 전달하도록 수정합니다.
# blog/views.py
def blog_list(request):
...
context = {
'object_list': page_object.object_list,
'page_obj': page_object,
}
return render(request, 'blog_list.html', context)
5️⃣ 페이지네이션 기능 추가 (CBV + FBV 공용)
{# blog_list.html 페이지네이션 영역 #}
<div>
{% if page_obj.has_previous %}
<a href="?page=1{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">« 첫번째</a>
<a href="?page={{ page_obj.previous_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">이전</a>
{% endif %}
{% if page_obj.number|add:2 > 1 %}
<a href="?page={{ page_obj.number|add:-3 }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">…</a>
{% endif %}
{% for i in page_obj.paginator.page_range %}
{% if page_obj.number == i %}
<span>(현재페이지)</span>
{% elif i > page_obj.number|add:-3 and i < page_obj.number|add:3 %}
<a href="?page={{ i }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">{{ i }}</a>
{% endif %}
{% endfor %}
{% if page_obj.paginator.num_pages > page_obj.number|add:2 %}
<a href="?page={{ page_obj.number|add:3 }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">…</a>
{% endif %}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">다음</a>
<a href="?page={{ page_obj.paginator.num_pages }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">마지막 »</a>
{% endif %}
</div>
{% endblock %}
✅ 정리
- CBV는 ListView 상속을 통해 더 간결하고 구조화된 코드 작성이 가능합니다.
- object_list, page_obj 등 변수명을 통일하면 FBV와 CBV가 같은 템플릿을 공유할 수 있습니다.
- 검색 기능과 페이지네이션도 CBV에서 유연하게 구현할 수 있습니다.
💡 제너릭 뷰는 기본 동작이 많아 생산성이 매우 높습니다. 꼭 활용해보세요!