Developer's Development

3.4.9 [Django] Class-based View(CBV) 본문

AI 활용 애플리케이션 개발/Django Framework

3.4.9 [Django] Class-based View(CBV)

mylee 2025. 10. 19. 23:52
CBV 개요

 

Django에서 클래스를 기반으로 View를 구성하는 방식이다.

- 기존의 함수형 뷰(Function-based view, FBV)는 단순하고 명확하지만, 복잡한 뷰 로직이 늘어나면 코드가 길어지고 유지보수가 어렵다.

- CBV는 상속과 메소드 오버라이딩을 통해 공통 기능을 재사용하고, 가독성과 확장성을 확보할 수 있다.

 

  • CBV의 기본 구조

ex) TemplateView

TemplateView는 단순히 템플릿만 렌더링할 때 사용하는 CBV이다.

- 브라우저 요청 → 해당 클래스 인스턴스 생성 → 내부 get() 메서드 실행 → 템플릿 렌더링

 

 

Generic CBV 종류
CBV 역할
ListView 객체 목록 조회
DetailView 단일 객체 상세 조회
CreateView 객체 생성 폼
UpdateView 객체 수정 폼
DeleteView 객체 삭제

 

👉🏻 모델 예시

# models.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=100)
    published_date = models.DateField()

 

  • ListView

- model: 조회 대상 모델

- template_name: 렌더링할 템플릿 파일

- context_object_name: 템플릿에서 사용할 객체 이름

from django.views.generic import ListView
from .models import Book

class BookListView(ListView):
    model = Book
    template_name = 'book_list.html'
    context_object_name = 'books'

 

  • DetailView

URL에 <int:pk>가 필요하다.

- path('books/<int:pk>/', BookDetailView.as_view())

from django.views.generic import DetailView

class BookDetailView(DetailView):
    model = Book
    template_name = 'book_detail.html'
    context_object_name = 'book'

 

  • CreateView

- success_url: 폼 제출 후 리다이렉션 할 경로

from django.views.generic.edit import CreateView
from .models import Book

class BookCreateView(CreateView):
    model = Book
    fields = ['title', 'author', 'published_date']
    template_name = 'book_form.html'
    success_url = '/books/'

 

  • UpdateView

기존 데이터를 폼에 채워주고 수정 가능하다.

from django.views.generic.edit import UpdateView

class BookUpdateView(UpdateView):
    model = Book
    fields = ['title', 'author', 'published_date']
    template_name = 'book_form.html'
    success_url = '/books/'

 

  • DeleteView
from django.views.generic.edit import DeleteView

class BookDeleteView(DeleteView):
    model = Book
    template_name = 'book_confirm_delete.html'
    success_url = '/books/'

 

 

CBV 오버라이딩 및 Method Flow

 

CBV 동작 방식

- CBV는 내부적으로 dispatch() 메서드를 통해 요청 메서드(GET, POST 등)를 구분한다.

 

👉🏻 메서드 오버라이딩 예

- form_valid(): 폼이 유효할 때 실행되는 메서드

- 필요한 곳에서 메서드만 오버라이딩하면 동작 제어 가능

class BookCreateView(CreateView):
    ...

    def form_valid(self, form):
        print("폼 유효성 검사 통과!")
        return super().form_valid(form)

 

 

MRO와 super()

 

다중 상속 기반

- CBV 내부 구조는 다중 상속으로 구성되므로 MRO(Method Resolution Order)를 이해해야 한다.

- super 함수는 MRO에 따라 부모 클래스 메서드를 호출

print(BookCreateView.__mro__)

 

 

실습

 

_04_django_form 프로젝트에서 그대로 진행

 

👉🏻 main/urls.py 추가

from .views import BookListView, BookDetailView, BookCreateView

urlpatterns = [
	...,
    
    path('books/', BookListView.as_view(), name='book_list'),
    path('books/<int:pk>', BookDetailView.as_view(), name='book_detail'),
    path('books/create', BookCreateView.as_view(), name='book_create'),
    # books/<int:pk>/update - url path 추가
    # books/<int:pk>/delete - url path 추가
]

 

👉🏻 main/views.py 수정

from .models import Book
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy

class BookListView(ListView):
    model = Book
    template_name = 'book_list.html'
    context_object_name = 'books'

class BookDetailView(DetailView):
    model = Book
    template_name = 'book_detail.html'

class BookCreateView(CreateView):
    model = Book
    form_class = BookForm
    template_name = 'book_form.html'
    success_url = reverse_lazy('main:book_list')

# BookUpdateView 작성

# BookDeleteView 작성

 

👉🏻 main/templates에 템플릿 HTML 추가 및 수정

book_form.html (수정)

...
<h1>도서 등록</h1>      <!-- [수정]이면 "도서 수정"으로 변경 -->
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">저장</button>
</form>

 

book_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>도서 목록</title>
</head>
<body>
    <h1>도서 목록</h1>
    <ul>
        {% for book in books %}
            <li><a href="{% url 'main:book_detail' book.pk %}">{{ book.title }}</a></li>
        {% empty %}
            <li>등록된 도서가 없습니다.</li>
        {% endfor %}
    </ul>
    <hr>    
    <a href="{% url 'main:book_create' %}">새 도서 등록</a>
</body>
</html>

 

book_detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ object.title }}</title>
</head>
<body>
    {# <p>{{ book }}</p> #}

    <h1>{{ object.title }}</h1>
    <p>저자: {{ object.author }}</p>
    <p>출판일: {{ object.published_date }}</p>
    <p>가격: {{ object.price }}</p>

    <a href="{% url 'main:book_list' %}">목록</a>

    <!-- 수정/삭제 추가 -->
    <!-- [수정] > book_form.html로 이동 (기존 book 정보 현출) > 수정사항 변경 후 [저장] > book_list.html 현출 -->
    <!-- [삭제] > book_confirm_delete.html로 이동 -->
</body>
</html>

 

book_confirm_delete.html

<h1>정말로 삭제하시겠습니까?😥</h1>
<p>대상 도서: {{ }}</p>

<!-- 삭제/취소 버튼 -->
<!-- [삭제] > 삭제 후 book_list.html 현출
     [취소] > 삭제하지 않고 book_detail.html로 복귀 -->