클래스 기반 뷰 (Class Based View) - ListView, DetailView

|

0. 들어가기

django를 사용하여 웹페이지를 만들다 보면 아래와 같은 view를 작성하는 경우가 많이 생긴다.

  1. 특정 DB table의 모든 record를 가져와서 List로 표시 (예: 게시판 글 목록 전체)
  2. 특정 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 }}">&laquo;</a></li>
  {% else %}
    <li class="disabled"><span>&laquo;</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 }}">&raquo;</a></li>
  {% else %}
    <li class="disabled"><span>&raquo;</span></li>
  {% endif %}
</ul>
{% endif %}


views
ListView에서 pagination 구현결과