본문 바로가기
Backend/Django

[Django] Django 학습 정리 - CBV (Class Based View)

by 요호유후 2025. 3. 30.
반응형

지금까지 Django 학습한 내용을 바탕으로 정리를 해보려 한다.

 

목차
1. CBV (Class Based View)
2. Django Generic Views
3. request(요청) 처리
4. response(응답) 관련 함수
[작업 환경]
MacOS, PyCharm
pyenv, poetry
Python, Django

 

 

1. CBV (Class Based View)

1. CBV란?

- Django에서 뷰를 클래스(Class)로 작성하는 방식이다.
- FBV에 비해 구조적이고 재사용성이 좋다.
- 요청 방식에 따라 def get(), def post() 와 같이 함수(클래스 메소드) 형태로 정의할 수 있다.

📌 '그래서 FBV보다 CBV가 무조건 좋다.' 이런 의미가 아니라,
     프로젝트 규모와 요구사항에 따라 적합한 방식을 선택하여 사용하면 된다. 

   

    ⭐️ FBV vs. CBV 비교

구분 FBV CBV
개념 뷰 로직을 함수로 작성 뷰 로직을 클래스로 작성
코드 구조 직관적이며 간단 구조적이고 재사용성이 높음
Django 요청
메소드 처리
if request.method == 'GET':
pass
elif request.method == 'POST':
pass
의 구조로 작성 (수동처리)
def get(), def post() 등
클래스 메소드 형태로 작성 가능

상속 받은 부모 클래스에 따라
Django 메소드 자동 인식 됨
코드 재사용 중복가능성 있음 믹스인(Mixin), 상속 등올 재사용 쉬움
코드 커스터마이징 자유도가 높음 Django 기본 메소드 오버라이딩 방식
😱 기본 속성, 메소드를 어느정도 알아야 함
테스트 용이성 상대적으로 용이 구조가 복잡할 수 있음

🧐 FBV 정리글 : https://jjincoding-helloworld.tistory.com/139

    📌 사용예시)

from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q
from django.http import HttpResponseRedirect, Http404
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.views.generic import ListView, CreateView, UpdateView, DeleteView

from blog.forms import CommentForm, BlogPostForm
from blog.models import Blog, Comment

# FBV-blog_list(request)와 동일
class BlogListView(ListView):
    queryset = Blog.objects.all()
    ordering = ('-created_at',)
    template_name = 'blog_list.html'
    paginate_by = 10

    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

# FBV-blog_detail와 동일
class BlogDetailView(ListView):
    model = Comment
    template_name = 'blog_detail.html'
    paginate_by = 10

    def get(self, request, *args, **kwargs):
        self.object = get_object_or_404(Blog, pk=kwargs.get('pk'))
        return super().get(request, *args, **kwargs)

    def get_queryset(self):
        return self.model.objects.filter(blog=self.object).prefetch_related('author')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['comment_form'] = CommentForm()
        context['blog'] = self.object

        return context

# FBV-blog_create와 동일
# LogiRequiredMixin = @login_required()
class BlogCreateView(LoginRequiredMixin, CreateView):
    model = Blog
    template_name = 'blog_form.html'
    form_class = BlogPostForm

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.author = self.request.user
        self.object.save()

        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        return reverse_lazy('blog:detail', kwargs={'pk':self.object.pk})

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['sub_title'] = '작성'
        context['btn_name'] = '생성'
        return context

# FBV-blog_update와 동일
class BlogUpdateView(LoginRequiredMixin, UpdateView):
    model = Blog
    template_name = 'blog_form.html'
    form_class = BlogPostForm

    def get_queryset(self):
        queryset = super().get_queryset()
        if self.request.user.is_superuser:  # if 혹은 if not 사용으로 분리해주면 됨
            return queryset # superuser면 전체 쿼리 반환
        return queryset.filter(author=self.request.user) # superuser 아니면 해당 user 정보의 쿼리만 출력

    def form_valid(self, form):
        print(form.cleaned_data) # cleaned_data : 출력값을 정리해서 보여줌
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['sub_title'] = '수정'
        context['btn_name'] = '수정'
        return context

# FBV-blog_delete와 동일
class BlogDeleteView(LoginRequiredMixin, DeleteView):
    model = Blog

    def get_queryset(self):
        queryset = super().get_queryset()
        if not self.request.user.is_superuser: # if 혹은 if not 사용으로 분리해주면 됨
            return queryset.filter(author=self.request.user)
        return queryset

    def get_success_url(self):
        return reverse_lazy('blog:list')

 

 

2. Django Generic Views

😆 Django Generic Views 클래스 정리

클래스 기능  사용 목적
CreateView 객체 생성 + 저장 게시글 작성, 회원가입 등
UpdateView 객체 수정 게시글 수정, 댓글 수정 등
ListView 객체 목록 조회 게시글 목록, 댓글 목록 등
DetailView 객체 상세 조회 게시글 상세, 사용자 정보 보기 등
DeleteView 객체 삭제 게시글 삭제, 댓글 삭제 등
TemplateView 템플릿만 보여줌 공지사항, 소개 페이지 등
FormView 커스텀 폼 처리 문의 폼, 피드백 등

 

⭐️ CBV에서 자주 사용되는 속성과 메소드 정리

구분 이름 설명
속성 model 연동할 모델 지정
form_class 사용할 폼 클래스 지정
template_name 사용할 템플릿 경로 지정
queryset 조회할 기본 쿼리셋 지정
get_queryset()을 통해 동적으로 처리 가능
success_url 작업 완료 후 리디렉션할 URL
get_success_url, get_absoulte_url() 대체 가능
reverse_lazy()와 함께 자주 사용됨
context_object_name 템플릿에서 사용할 객체 이름 변경
기본이 'object_list, object' 임
paginate_by 페이지당 항목 수 지정
주로 ListView에서 사용
메소드 get_queryset() 쿼리셋을 동적으로 정의
필터링, 정렬 등에 활용
get_object() 조회할 단일 객체를 커스터마이징할 때 사용
get_form_class() 사용할 폼 클래스를 동적으로 지정할 때 사용
get_form() 폼 인스턴스를 커스터마이징할 때 사용
form_valid(form) 폼 검증에 성공했을 때 호출 됨
주로 저장/처리 로직 작성 함
get_success_url() 작업 성공 후 이동할 URL을 동적으로 반환할 때 사용
get_context_data() 템플릿에 넘길 context 데이터를 확장/커스터마이징할 때 사용
get(), post(), patch(), delete() 등 요청 메소드 처리에 사용

1. CreateView

객체를 생성하는 폼을 제공하고 제출된 데이터를 저장하는 뷰 클래스이다.
model, success_url(혹은 get_success_url() 메소드) 을 필수속성으로 갖는다. 
   * models.py에 get_absolute_url() 메소드 정의 되어있으면 success_url 없어도 됨
   * 즉, success_url, get_success_url(), get_absolute_url() 셋 중 하나는 작성되어야 함!!

    📌 사용예시)

class BlogCreateView(LoginRequiredMixin, CreateView):
    model = Blog	# 어떤 모델에 저장할지 (필수 속성)
    template_name = 'blog_form.html'	# 랜더링할 템플릿 지정
    # fields = ('category', 'title', 'content') # forms.py 대신으로 이렇게 사용함
    form_class = BlogPostForm	# 사용할 폼 클래스 (fields 대신 사용, 동시 사용 불가)

    def form_valid(self, form):	# 폼이 유효할 때 실행됨
        self.object = form.save(commit=False)	# 유저정보를 담은 후 저장하기 위함
        self.object.author = self.request.user	# 유저정보 할당
        self.object.save()

        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):	# 저장 성공 시 이동할 URL (success_url 속성으로 할당 가능) (필수)
        return reverse_lazy('blog:detail', kwargs={'pk':self.object.pk})

    def get_context_data(self, **kwargs):	# 템플릿에 넘겨줄 데이터가 있을 경우 사용
        context = super().get_context_data(**kwargs)
        context['sub_title'] = '작성'
        context['btn_name'] = '생성'
        return context

 

2. UpdateView

기존 객체의 정보를 수정하는 폼을 제공하고 수정된 데이터를 저장하는 뷰 클래스이다.
model, success_url(혹은 get_success_url() 메소드) 을 필수속성으로 갖는다. 
   * models.py에 get_absolute_url() 메소드 정의 되어있으면 success_url 없어도 됨   
   * 즉, success_url, get_success_url(), get_absolute_url() 셋 중 하나는 작성되어야 함!!

    📌 사용예시)

class BlogUpdateView(LoginRequiredMixin, UpdateView):
    model = Blog	# 필수속성
    template_name = 'blog_form.html'
    form_class = BlogPostForm

    def get_queryset(self):	# 수정할 현재 데이터 불러옴
        queryset = super().get_queryset()
        if self.request.user.is_superuser:  
            return queryset # superuser면 전체 쿼리 반환
        return queryset.filter(author=self.request.user) # superuser 아니면 해당 user 정보의 쿼리만 출력

    def form_valid(self, form):
        print(form.cleaned_data) # cleaned_data : 출력값을 정리해서 보여줌
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['sub_title'] = '수정'
        context['btn_name'] = '수정'
        return context

 

3. ListView

특정 모델에 대한 객체 목록을 조회하고 이를 템플릿에 전달해서 랜더링하는 뷰 클래스이다.

    📌 사용예시)

class BlogListView(ListView):
    # model = Blog => Blog.objects.all() 과 같음 // order_by() 등 함수사용 시 아래와 같이 작성
    # queryset = Blog.objects.all().order_by('-created_at') # 혹은 ordering 변수로 선언할 수 있음
    queryset = Blog.objects.all()
    ordering = ('-created_at',)
    template_name = 'blog_list.html'
    paginate_by = 10
    
    # for문에 들어가는 model 데이터들을 obejct_list 라는 변수명으로 받는다.
    # 그래서 object_list 변수명을 사용해야 함!!

    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

 

4. DetailView

DB에 저장된 특정 객체 1개를 상세히 보여주는 뷰 클래스이다.
URL에 식별자(pk, id, slug 등)을 받아서 해당 객체를 가져와 템플릿에 전달한다.

    📌 사용예시)

class UserProfileView(DetailView):
    model = User
    template_name = 'profile/detail.html'
    slug_field = 'nickname'
    slug_url_kwarg = 'slug'
    queryset = User.objects.all()\
        .prefetch_related('post_set', 'post_set__images', 'following', 'followers')

 

5. DeleteView

특정 객체를 삭제할 수 있는 뷰 클래스이다.
삭제 확인용 템플릿을 보여주고 POST 요청 시 삭제가 실행된다.

   📌 사용예시)

class BlogDeleteView(LoginRequiredMixin, DeleteView):
    model = Blog

    def get_queryset(self):
        queryset = super().get_queryset()
        if not self.request.user.is_superuser:
            return queryset.filter(author=self.request.user)
        return queryset

    def get_success_url(self):
        return reverse_lazy('blog:list')

 

 

3. request(요청) 처리
구분 설명 코드 예시
request.user 현재 요청을 보낸 로그인된 사용자 정보 request.user.username,
request.user.is_authenticated
request.POST POST 요청으로 전달된 데이터
(form 전송 등)
request.POST.get('title')
reuquest.GET GET요청의 쿼리 파라미터
(검색, 필터 등)
request.GET.get('q')
request.FILES 업로드된 파일 데이터 접근 request.FILES['image']
request.method 요청방식(GET, POST 등) if request.method == 'POST':
pass

 

4. response(응답) 관련 함수
구분 설명 예시코드
HttpResponseRedirect() 특정 URL로 리다이렉트
(페이지 이동)
return HttpResponseRedirect('/login/')
HttpResponse() 직접 문자열, HTML 등을 반환
(단순 응답)
return HttpResponse("Hello World")
status code 응답 상태를 나타내는 숫자 코드 return HttpResponse
("Forbidden", status=403)
response data JSON 형식으로 응답 {"title":"제목1", "content":"본문1"}

    📌 status code

상태코드 설명
200 요청 성공
302 리다이렉트
400 잘못된 요청
403 권한 없음
404 존재하지 않음
500 서버오류

 

 

 

반응형

댓글