Django : python으로 웹서비스 개발하기(12) - 클래스 기반 뷰 적용하기

harry jang·2023년 8월 9일
0

Django

목록 보기
12/12
post-thumbnail

Django클래스 기반 뷰(class-based views)라는 함수가 아닌 파이썬 객체를 이용하여 뷰를 생성하는 방법도 제공합니다. 클래스 기반 뷰는 함수 기반 뷰와는 달리 다음 장점을 갖고 있습니다.

  • 특정 HTTP 메서드(GET, POST 등)와 관련된 코드를 조건 분기 대신 별도의 메서드를 사용하여 처리할 수 있습니다.
  • 다중상속(multiple inheritance)과 같은 객체 지향 기법을 사용하여 코드를 재사용 가능한 구성 요소로 분리할 수 있습니다.

그리고 뷰 개발에서 흔히 발견되는 관용구와 패턴을 추상화하고 일반적인 경우에 뷰 개발을 용이하게 하기 위해 자주 쓰는 클래스 기반 뷰들을 미리 만들어서 제공하고 있는데, 이 뷰를 제네릭 뷰라고 합니다.

Django에서 제공하는 클래스 기반 뷰 및 제네릭 뷰에 대한 자세한 정보는 아래 링크를 참고바랍니다.

Built-in class-based views API

자 그러면 지금까지 만든 코드에 이것을 한 번 적용해봅시다.

뷰 파일 수정하기

먼저, 기존에 함수 기반 뷰로 작성된 test_app/views.py파일의 해당 부분을 수정해봅시다.

...
def index(request):
    latest_book_list = TestBook.objects.order_by("-reg_datetime")[:5]
    context = {"latest_book_list" : latest_book_list,}
    return render(request, "book/index.html", context)

def book(request, book_id):
    book = get_object_or_404(TestBook, pk=book_id)
    return render(request, "book/detail.html",  {"book": book, "range":range(10)})

def comment(request, book_id):
...

아래는 클래스 기반 뷰로 변경한 형태입니다.

...
from django.views.generic import (
    ListView,
    DetailView,
)

class BookIndexView(ListView):
    template_name = "book/index.html"
    context_object_name = "latest_book_list"
    
    def get_queryset(self):
        return TestBook.objects.order_by("-reg_datetime")[:5]
    
class BookDetailView(DetailView):
    model = TestBook
    template_name = "book/detail.html"
    context_object_name = 'book'
    
    def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
        context_data = super().get_context_data(**kwargs)
        context_data['range'] = range(10)      
        return context_data
    
def comment(request, book_id):
...

기존 index() 함수는 BookIndexView 클래스로 전환되었으며 BookIndexView는 목록의 형태로 데이터를 보여주기 때문에 ListView라는 제네릭뷰를 상속받도록 설정합니다.

Python 언어에서의 상속은 아래와 같은 형태로 상속관계를 설정할 수 있습니다.

class 클래스명(상속받을 부모클래스명)

함수의 입력 파라미터와 형태가 비슷해 보이나 전혀 다른 개념이므로 혼동되지 않도록 합니다.

그리고 필요한 값들을 미리 정해둔 변수값에 입력받는 형식으로 작성을 하게 됩니다. BookIndexView 예시는 template_name 변수에 사용자 화면에 바탕이 될 템플릿의 이름(파일경로)를 작성하고, context_object_name값을 설정하여 화면에 목록으로 보여질 모델의 목록 객체의 이름을 'latest_book_list'로 선언했습니다.

그리고 화면에 뿌려질 모델을 가져오기 위한 메서드인 get_queryset() 함수는 기존에 모델을 최근 5개까지의 모델들을 목록으로 리턴하도록 재정의(override)하였습니다.

목록을 보여주는 뷰 뿐만 아니라 실제 다른 제네릭 뷰를 사용하더라도 위 예시와 같이 용도에 맞는 제네릭 뷰 클래스를 상속받게 설정한 후 부모클래스에서 미리 정의된 멤버변수에 필요한 값들을 채워 넣고 필요한 메서드를 재정의(override)하는 형식으로 구현된다고 보시면 됩니다.

기존 book 함수도 BookDetailView 클래스로 전환되었으며, 마찬가지로 제네릭 뷰의 DetailView를 상속받아서 구현되었습니다.

model변수에 모델로 사용할 테이블 모델 클래스를 지정하고, template_namecontext_object_name에 각각 화면에 노출시킬 템플릿 명과 그 템플릿을 이용하여 화면에 그릴 때 필요한 모델 객체 데이터를 담을 변수의 이름을 선언했습니다.
context_data라는 딕셔너리 객체에 range라는 키를 추가하여 템플릿에서 평점 입력을 위한 라디오 버튼을 생성할 때 필요한 값을 함께 리턴하도록 재정의(override)하였습니다.

참고로 context_object_name은 별도로 설정하지 않으면 기본값으로 모델 객체가 내려가게 됩니다. 하지만 기본값을 사용하지 않고 수정한 이유는 만들어 두었던 템플릿 파일을 그대로 활용할 수 있게 하기 위함입니다.

예를 들어 기존에 작성해뒀던 templates/book/index.html를 한 번 살펴봅시다.

templates/book/index.html

<h3>신간도서</h3>
{% if latest_book_list %}
<ul class="list-group">
  {% for book in latest_book_list %}
  <li>
    <a href="{% url 'bookstore:detail' book.id %}">{{ book.title }}</a>
  </li>
  {% endfor %}
</ul>
{% else %}
<p>No books are available.</p>
{% endif %}

views.py에서 context_object_name을 이미 기존 템플릿 파일내에서 사용하는 이름으로 바꿔주었기 때문에 템플릿 파일들은 별도 수정없이 그대로 사용할 수 있게 되었습니다.

context_object_name의 기본값은 제네릭 뷰가 상속받는 Mixin에 따라 이름이 결정됩니다. 예를 들어 제네릭 뷰가 SingleObjectMixin을 상속받는 단일 개체를 위한 뷰라면 모델명이 곧 이름이 됩니다. 하지만 ListView와 같이 복수 개체를 위한 뷰라면 MultipleObjectMixin을 상속받기 때문에 모델명 뒤에 '_list'라는 이름으로 디폴트 값이 정해지게 됩니다.
ex)
Book 모델 단일 개체용 뷰에서의 기본값 : book
Book 모델 복수 개체용 뷰에서의 기본값 : book_list

믹스인(Mixin) 이란?
Mixin은 python에서 제공하는 다중상속을 활용한 클래스의 한 종류입니다. 하지만 일반적인 클래스 상속의 개념과는 다르게 재사용되는 코드의 파편, 즉 스스로는 별 의미를 가지지 않지만 상속받는 클래스에게 부가적인 기능을 추가시켜주는 용도로 사용하는 클래스입니다.

URL 설정파일 수정하기

다음으로 만들어진 클래스 기반뷰로 라우팅 되도록 test_app/urls.py 파일도 수정해 줍니다.

...
from . import views

app_name = "bookstore"
urlpatterns = [
	path("", views.BookIndexView.as_view(), name="index"),
    path("<int:pk>/", views.BookDetailView.as_view(), name="detail"),
...
]

이번 포스팅에서는 함수 기반 뷰를 클래스 기반 뷰로 전환하는 방법을 정리하였고, 다음 포스팅에 클래스 기반뷰와 폼을 사용하여 서평을 등록하는 코드를 개선해 보겠습니다.
profile
software engineer

1개의 댓글

comment-user-thumbnail
2023년 8월 9일

정보에 감사드립니다.

답글 달기