클래스 기반 뷰 (Class Based View) - ListView, DetailView
02 May 2017 | python Django CBV pagination0. 들어가기
django를 사용하여 웹페이지를 만들다 보면 아래와 같은 view를 작성하는 경우가 많이 생긴다.
- 특정 DB table의 모든 record를 가져와서 List로 표시 (예: 게시판 글 목록 전체)
- 특정 DB table의 톡정 record를 가져와서 Detail 내용 표시 (예 : 게시판의 특정 글 상세 내용)
파이썬 웹프로그래밍 책의 내용 중 동일한 view를 FBV(Function Based View) 와 CBV (Class Based View) 로 각각 구현하는 부분이 있었다. 해당 내용을 실습하며 용도에 맞춰 사용한다면 CBV를 활용해서 더 간단하게 view를 구현할 수 있다는 걸 알 수 있었다.
1. 글 목록 전체 표시 (List)
1-1. FBV 를 활용하여 글 목록 전체 표시
- urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
- views.py
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5] # 최근 5개의 질문 리스트만 가져온다.
context = {'latest_question_list' : latest_question_list}
return render(request, 'polls/index.html', context)
1-2. CBV - ListView 를 활용하여 글 목록 전체 표시 (예시1)
- 게시판의 글 목록 전체를 표시하거나, 특정 DB table의 record 전체 (혹은 일부)를 List로 표시할 때 활용할 수 있다.
- 리스트가 테이블의 모든 레코드인 경우 모델 클래스만 지정하면 된다.
- urls.py
from bookmark.views import BookmarkLV
urlpatterns = [
url(r'^bookmark/$', BookmarkLV.as_view(), name='index' ),
]
- views.py
from django.views.generic import ListView
from bookmark.models import Bookmark
class BookmarkLV(ListView):
"""
ListView 디폴트 지정 속성
1) 컨텍스트 변수 : object_list
2) 템플릿 파일 : bookmark_list.html (모델명소문자_list.html)
"""
model = Bookmark
1-3. CBV - ListView 를 활용하여 글 목록 전체 표시 (예시2)
- urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'), # as_view() 클래스 함수를 통해 함수뷰 생성
]
- views.py
from django.views.generic import ListView
from .models import Question
class IndexView(ListView):
template_name = 'polls_cbv/index.html' # 디폴트 템플릿명: <app_label>/<model_name>_list.html
context_object_name = 'question_list' # 디폴트 컨텍스트 변수명 : object_list
def get_queryset(self): # 컨텍스트 오버라이딩
return Question.objects.order_by('-pub_date')[5:]
- 디폴트 설정을 그대로 사용한다면 아래와 같이 간단하게 작성할 수 있다.
from django.views.generic import ListView
from .models import Question
class IndexView(ListView):
def get_queryset(self): # 컨텍스트 오버라이딩
return Question.objects.order_by('-pub_date')[5:]
2. 특정 글 상세 표시 (Detail)
- 게시판 글 상세내용을 표시하는 것과 같이, 특정 DB table의 특정 record 상세내용을 표시할 때 활용할 수 있다.
- 조회시 사용할 Primary Key 값은 URLconf에서 추출하여 뷰로 넘어온 파라미터(PK) 를 사용한다.
2-1. FBV 를 활용하여 특정 글 상세내용 표시
- urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<question_id>\d+)/$', views.detail, name='detail'),
]
- views.py
from django.shortcuts import get_object_or_404, render
from .models import Question
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {
'question': question,
})
2-2. CBV - DetailView 를 활용하여 특정 글 상세내용 표시 (예시 1)
- urls.py
from bookmark.views import BookmarkDV
urlpatterns = [
url(r'^bookmark/(?P<pk>\d+)/$', BookmarkDV.as_view(), name='detail'),
]
- views.py
from django.views.generic import DetailView
from bookmark.models import Bookmark
class BookmarkDV(DetailView):
"""
DetailView 디폴트 지정 속성
1) 컨텍스트 변수 : object (URLConf 에서 pk 파라미터 값을 활용하여 DB 레코드 조회)
2) 템플릿 파일 : bookmark_detail.html (모델명소문자_detail.html)
"""
model = Bookmark
2-3. CBV - DetailView 를 활용하여 특정 글 상세내용 표시 (예시 2)
- urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
]
- views.py
from django.views.generic import DetailView
from .models import Question
class DetailView(DetailView):
model = Question # 해당 모델 - URLConf 의 PK 변수를 활용하여 해당 모델의 특정 record를 컨텍스트 변수(object)에 담는다.
template_name = 'polls_cbv/detail.html' # 디폴트 템플릿명: <app_label>/<model_name>_detail.html
context_object_name = 'question' # 디폴트 컨텍스트 변수명 : object
- 디폴트 설정을 그대로 사용한다면 아래와 같이 간단하게 작성할 수 있다.
from django.views.generic import DetailView
from .models import Question
class DetailView(DetailView):
model = Question
3. (참고) CBV - ListView 에서 pagination 구현하기
- views.py
class IndexView(ListView):
model = Question
paginate_by = 10 # 한 페이지에 보여줄 오브젝트의 갯수
- 템플릿
<h2>설문조사 질문 리스트</h2>
{% if object_list %}
<ul>
{% for question in object_list %}
<li><a href="{% url 'polls_cbv:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>설문조사 목록이 없습니다.</p>
{% endif %}
<!-- bootstrap style을 적용한다. -->
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li><a href="?page={{ page_obj.previous_page_number }}">«</a></li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li><a href="?page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li><a href="?page={{ page_obj.next_page_number }}">»</a></li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}