Django CBV

Haks.·2025년 1월 22일
0

How to use

목록 보기
14/32

📖 Django CBV

Class Based View

  • 장점

    • 재사용 용이
    • 잘 쓸경우 코드가 짧아지는 효과
    • 구조가 나눠져 있어 코드 가독성 증가
  • 단점

    • 배워야 하는게 많아짐
    • 잘 모르고 쓸 경우 너무 어렵고 복잡
  1. urls.py 설정
    path('about/', TemplateView.as_view(template_name='about.html'), name='about'),
  1. about.html 생성
  2. 이렇게만 해도 페이지 단에 나옴, 함수작성 0
  3. CBV를 사용해서 하면
  4. urls.py 에 작성
  5. redirect 까지 작성, pattern_name= path 이름
# cb_views.py
class AboutView(TemplateView):
    template_name = 'about.html'

# path 에
    path('about/', AboutView.as_view(), name='about'),
    path('redirect/', RedirectView.as_view(pattern_name='about'), name='redirect'),
    # path('redirect2/', lambda req: redirect('about')), 별로
  1. view
class TestView(View): # get 요청일땐 get 요청만 post 요청일땐 포스트만 받는 함수 MeathodView 인가? flask
    def get(self, request):
        return render(request, 'test_get.html')
    def post(self, request):
        return render(request, 'test_post.html')
# 이렇게 하면 test 페이지 하나 안에서 get 요청과 post 요청 두가지 전부 처리할 수 있다.

# path
    path('test/', TestView.as_view(), name='test'),
  1. RedirectView 는 patter_name 을 입력하면 거기에 해당하는 path name 을 가르키게 함,reverse 와 같은 효과

📝 ListView

  • ListView는 기본적으로 템플릿으로 아래의 context 변수를 전달합니다:
    • page_obj: 현재 페이지와 관련된 정보를 포함하는 Page 객체.
    • paginator: 전체 페이지네이션을 관리하는 Paginator 객체.
    • object_list: 현재 페이지의 객체 리스트.
  1. cb_views.py
  2. html 안의 원래 모든 객체를 받았던 요소들, object_list 로 들어감
  3. 페이지네이션의 객체는 page_obj
# cb_views.py

from django.views.generic import ListView
from django.db.models.query_utils import Q


class BlogListView(ListView):
	# model = Blog # 블로그 모들에 모든 객체를 가져온다 ,objects.all() 임
    # 필터해서 가져오고 싶으면, 또는 order by를 쓰고싶으면
    queryset = Blog.objects.all().order_by('-created_at')
    # ordering = ('created_at') 이렇게 써도 된다
    #  ListView를 상속받는 순간 자동으로 queryset = Model.objects.all()이 설정
    
    
    template_name = 'blog_list.html' # 여기로 자동 렌더링
    paginate_by = 10 # 10개 개단위로 페이지네이트
    
    def get_queryset(self): # ListView에 내장되어 있는 함수
    	queryset = super().get_queryset() # 상속받은 쿼리셋 가져오기
        q = self.request.GET.get('q') # q에 해당하는 값 페이지로부터 받으면, 아래 조건 적용 (검색 기능임)
        if q:
        	queryset = queryset.filter(
            	Q(title__icontains = q) | # Q 는 장고 내장 모듈임
                Q(content__icontains = q)
                )
        return queryset

# blog/urls.py

from django.urls import path
from blog import cb_views

app_name = 'blog' # appname 을 지정해주지 않으면 html 에서 blog:detial 을 사용하지 못하고 name 을 지정해 주어야 한다.

urlpattenrs = [
	path('', cb_views.BlogListView.as_view(), name = 'list'),
]
# config/urls.py
from django.urls import path, include
urlpatterns =[
	path('', include('blog.urls'),
]

📝 DetailView

  • DetailView 기본적으로 템플릿으로 아래의 context 변수를 전달합니다:
    • object: DetailView의 가장 중요한 컨텍스트 변수, get_object() 메서드로 가져온 객체가 저장됩니다.
    • 모델 이름이 Blog라면, blog라는 변수도 추가됩니다.
blog/cb_views.py
from django.views.generic import DetailView

class BlogDetailView(DetailView): # DetailView 상속
	model = Blog
    template_name = 'blog_detail.html
  1. model = Blog 면 템플릿에서 사용되는 객체의 이름은 blog 이다.
  2. 전체 말고 filter, 또는 pk 를 받아서 사용하는 방법
# cb_views.py

class BlogDetailView(DetailView):
	model = Blog
    template_name = 'blog_detail.html'
    
    # 50 이상인 것만 받아오기
    # 상속받은 detailview get_queryset 불러오기
    def get_queryset(self):
    	queryset = super().get_queryset()
        return queryset.filter(id__lte=50) # /60 을 넣으면 404 페이지 발생
    
    # 기본적인 동작은 기본 이랑 같으나 오버라이드나,
    # 특정 상태의 블로그만 보여줄때, 접근권한을 제한하고 싶을 떄
    # url에 포함된 키 외에 다른 조건으로 객체를 조회할 떄
    # 조회 전에 다른 작업을 수행하거나 로그를 남겨야 할 때
    def get_object(self, queryset = None):
    	object = super().get_object() # pk 또는 slug 를 url 에서 자동으로 추출하여, 기본적으로 저장된 model 클래스에서 객체를 가져옴
		# 위아래 같은 동작
        object = self.model.objects.get(pk=self.kwargs.get('pk'))
        return object
        
    # context를 사용하고 싶은 경우, 하나하나의 내용을 쓰고싶을때
    def get_context_data(self, **kwargs):
    	context = super().get_context_data(**kwargs) #context 에 object 라는 키를 넣은것이고 거기에 해당하는 값을 모델에서 가져와 하나씩 넣은것임 그래서 아래처럼 굳이 안써도되긴함
        blog = self.object # pk를 받아서 하나의 객체 넣기 # object 로 하나씩 받은것
        context['data'] ={
        	'title' : blog.title,
            'content' : blog.content
        }
        # 위와 같이 안하고
		context['data'] ={
        	'title' : context['object'].title
        } # 이런식으로 새로운 키에 값을 넣어 줄 수 있다.
        return context # 이렇게 사용하면 html 에서 data.title을 사용할 수 있다.
 
# blog/urls.py

from django.urls import path
from blog import cb_views

app_name = 'blog' # appname 을 지정해주지 않으면 html 에서 blog:detial 을 사용하지 못하고 name 을 지정해 주어야 한다.

urlpattenrs = [
	path('', cb_views.BlogListView.as_view(), name = 'list'),
    path('<int:pk>/', cb_views.BlogDetailView.as_view(), name = 'detail'),
]
        

📝 CreateView

  • DetailView 기본적으로 템플릿으로 아래의 context 변수를 전달합니다:
    • form: 지정한 fields에 해당하는 것을 불러옵니다. {{ form.as_p }}
    • view {{ view.model }} 또는 {{ view.__class__.__name__ }}를 통해 뷰와 관련된 정보를 출력할 수 있습니다.
  1. 기본구성과 CreateView 의 객체 form을 위해 fields를 만들어준다.
  2. 로그인이 되어있어야 하기에 장고의 로그인 기능을 가진 모듈을 상속시켜준다. LoginRequiredMixin
  3. Foreginkey 를 필드에 적용시켜서 사용할 수도 있으나 그러면 일반 사용자가 다른 author 를 지정할 수도 있기에, commit=false를 사용해서 처리한다. 현재 까지 작성해보면.
from django.views.generic import DetailView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy

class BlogCreateView(LoginRequiredMixin, CreateView):
	model = Blog
    template_name = 'blog_create.html'
    fields = ('title', 'content')
    success_url = reverse_lazy('blog:list')
    # reverse_lazy 를 쓰는 이유는 보통의 reverse 는 즉시 실행 되는데 reverse lazy 는 호출을 지연시킨다
    # 즉 실제로 URL 이 필요할때 (예: 뷰가 실행되는 시점) 에서 호출됩니다.
    
    def form_valid(self, form): # 상속받은 createview의 메서드
    	# FBV 에서 한것 처럼 blog =form.save(commit=False)
        self.object = form.save(commit = False)
        self.object.author = self.request.user
        self.object.save()
        return HttpResponseRedirect(self.get_success_rul()) 
        # httpresponse 모듈을 등록해준 후 상속받은 함수인 get_success_url 함수를 실행시켜 등록된 url 로 보낸다.
# 명시적으로 def get_success_url(self): 를 등록시키지 않으면 이 url은
# 모델에 있는 아래의 함수로 들어간다 명시적으로 등록시키면 해당하는 곳으로간다
	def get_success_url(self):
    	return reverse_lazy('blog:list')
# 이 함수는 모델에서 등록시켜 놔야한다.
# blog/models.py의 blog 클래스 안에 등록
#     def get_absolute_url(self):
#         return reverse('blog:list', kwargs={'pk':self.pk})

# blog/urls.py

from django.urls import path
from blog import cb_views

app_name = 'blog' # appname 을 지정해주지 않으면 html 에서 blog:detial 을 사용하지 못하고 name 을 지정해 주어야 한다.

urlpattenrs = [
	path('', cb_views.BlogListView.as_view(), name = 'list'),
    path('<int:pk>/', cb_views.BlogDetailView.as_view(), name = 'detail'),
    path('create/', cb_views.BlogCreateView.as_view(), name = 'create'),
]

📝 UpdateView

  • DetailView 기본적으로 템플릿으로 아래의 context 변수를 전달합니다:
    • form: 지정한 fields에 해당하는 것을 불러옵니다. {{ form.as_p }}
    • object: 설정한 모델을 불러올 수 있습니다. {{ object.title }}
    • view
  • 업데이트 클래스 생성, 로그인 포함
from django.views.generic import UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin

class BlogUpdateView(LoginRequiredMixin, UpdateView):
	model = Blog
    template_name = 'blog_update.html'
    fields = ('title', 'content') # 수정할 필드
    
    # 기본적인 방법
    def get_success_url(self):
    	return reverse_lazy('blog:detail', kwargs ={'pk':self.object.pk})
        
    # 방법2 models에 업데이트 동작을 작성자만 하게 만들고 싶은 경우
    def get_queryset(self):
    	queryset = super().get_queryset()
        return queryset.filter(author=self.request.user)
    # 1.BlogUpdateView는 URL에서 pk 값을 가져옵니다.
	# 2.get_queryset으로 현재 사용자가 작성한 게시글만 조회합니다.
	# 3.해당 게시글이 존재하면, 폼을 렌더링합니다.
	# 4.사용자가 데이터를 수정하고 제출하면:
	# 	•	제출된 데이터를 Blog 객체에 저장합니다.
	# 	•	저장 성공 후 get_absolute_url이나 명시적으로 정의된 get_success_url로 리디렉션합니다.
    
    # 방법 3
    def get _object(self, queryset = None):
    	self.object = super().get_object(queryset)
        if self.object.author != self.request.user:
        	raise Http404
        return self.object

# blog/urls.py

from django.urls import path
from blog import cb_views

app_name = 'blog' # appname 을 지정해주지 않으면 html 에서 blog:detial 을 사용하지 못하고 name 을 지정해 주어야 한다.

urlpattenrs = [
	path('', cb_views.BlogListView.as_view(), name = 'list'),
    path('<int:pk>/', cb_views.BlogDetailView.as_view(), name = 'detail'),
    path('create/', cb_views.BlogCreateView.as_view(), name = 'create'),
    path('<int:pk>/update/', cb_views.BlogUpdateView.as_view(), name = 'update'),
]

📝 DeleteView

  • DetailView 기본적으로 템플릿으로 아래의 context 변수를 전달합니다:
    • 모델 이름을 불러 올 수 있습니다. Blog 라면 blog
    • object: 설정한 모델을 불러올 수 있습니다. {{ object.title }}
    • get_context_data 메서드를 오버라이드 하여 컨텍스트에 데이터를 추가 할 수 있습니다.
  1. template 이 필요하지 않으니 모델만 불러오면 된다.
  2. author랑 현재유저랑 같은지 찾는 함수를 만든다.

class BlogDeleteView(LoginRequiredMixin, DeleteView):
	model = Blog
    
    def get_queryset(self):
    	queryset = super().get_queryset()
        return queryset.filter(author = self.request.user))
    # 성공적으로 동작을 했을때 보낼 url
    def get_success_url(self):
    	return reverse_lazy('blog:list')

# blog/urls.py

from django.urls import path
from blog import cb_views

app_name = 'blog' # appname 을 지정해주지 않으면 html 에서 blog:detial 을 사용하지 못하고 name 을 지정해 주어야 한다.

urlpattenrs = [
	path('', cb_views.BlogListView.as_view(), name = 'list'),
    path('<int:pk>/', cb_views.BlogDetailView.as_view(), name = 'detail'),
    path('create/', cb_views.BlogCreateView.as_view(), name = 'create'),
    path('<int:pk>/update/', cb_views.BlogUpdateView.as_view(), name = 'update'),
    path('<int:pk>/delete/', cb_views.BlogDeleteView.as_view(), name='delete'),
]

📝 URL include

개발자들은 반복적인 것을 싫어해서 반복을 줄이려고 노력함
앞부분을 지정해놓으면 앞부분을 사용하지 않고 뒷부분만 사용해서 되게하는 것

    path('accounts/', include("django.contrib.auth.urls")),
  • app_name
  • reverse, html url 의 경로는 전부 name 값 그값을 app_name:name 으로 사용해야함

📌 모듈 정리

from django.contrib.auth.mixins import LoginRequiredMixin # loginrequired랑 같은 기능
class BlogCreateView(LoginRequiredMixin, CreateView):

from django.views.generic import DetailView, CreateView, UpdateView, DeleteView, ListView
class BlogListView(ListView)
class BlogUpdateView(LoginRequiredMixin,UpdateView)
class BlogCreateView(CreateView)
class BlogDetailView(DetailView): 
class BlogDeleteView(LoginRequiredMixin, DeleteView)

from django.views.generic import TemplateView, RedirectView
    path('about/', TemplateView.as_view(template_name='about.html'), name='about'),
    path('redirect/', RedirectView.as_view(pattern_name='about'), name='redirect'),

from django.views import View
class TestView(View)

from django.views.generic import ListView
class BlogListView(ListView):

from django.db.models.query_utils import Q
queryset = queryset.filter(
                Q(title__icontains=q) |
                Q(content__icontains=q)
            )

from django.http import HttpResponseRedirect
        return HttpResponseRedirect(self.get_success_url()) # 이게일단 기본값

from django.urls import reverse_lazy
    success_url = reverse_lazy('cb_blog_list')

🧹 Tip

  • 파이참 기능 커맨드+R : 찾기 + 수정
  • 내가설정해 놓은것 컨트롤 + a,z : 위아래로 해당영역 설정
  • 거기서 움직이려면 움직이면 다같이 움직임 선택하려면 쉬프트 누르고 오른쪽
  • 옵션누르고 움직이면 단어별로 움직임
  • command + shift + f: 전체검색
  • context로 모든 한객체의 모든 필드를 불러올려면
def get_context_data(self, **kwargs):
	context = {'todo': self.object.__dict__}
    return context

Django CBV get_context_data() 기본 컨텍스트

Django의 DetailView, ListView, CreateView, UpdateView 같은 CBV(Class-Based View)는 자동으로 특정 기본 컨텍스트를 제공합니다.
이 컨텍스트는 템플릿에서 데이터를 쉽게 사용할 수 있도록 돕습니다.


1. 기본 컨텍스트에 포함된 데이터

DetailView

  • 개별 객체를 조회할 때 사용합니다.

  • 기본 컨텍스트:

    키 (context 내부 값)설명
    object현재 조회 중인 모델 객체 (self.object)
    view현재 실행 중인 뷰 클래스 (self)
    kwargsURL 패턴에서 전달된 인자 (예: pk, slug)

ListView

  • 모델의 객체 리스트를 조회할 때 사용합니다.

  • 기본 컨텍스트:

    키 (context 내부 값)설명
    object_list현재 모델의 전체 리스트 (QuerySet)
    view현재 실행 중인 뷰 클래스 (self)
    paginatorListView에서 페이징을 사용할 경우 Paginator 객체
    page_obj현재 페이징된 페이지 정보

CreateView, UpdateView, DeleteView

  • 객체를 생성, 업데이트, 삭제할 때 사용합니다.

  • 기본 컨텍스트:

    키 (context 내부 값)설명
    form현재 뷰에서 사용되는 ModelForm 객체
    objectUpdateView, DeleteView에서 수정/삭제 대상 객체
    view현재 실행 중인 뷰 클래스 (self)

2. get_context_data() 활용법

기본 컨텍스트 + 추가 데이터

Django 기본 컨텍스트를 유지하면서, 추가 데이터를 전달하는 방법:

class TodoInfoView(LoginRequiredMixin, DetailView):
    model = Todo
    template_name = 'todo_info.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)  # 기본 컨텍스트 유지
        context['extra_info'] = 'This is extra info'  # 추가 데이터 전달
        return context

기본 컨텍스트를 유지하지 않는 경우

super().get_context_data()를 호출하지 않으면, 기본 컨텍스트가 사라집니다.

def get_context_data(self, **kwargs):
    context = {'todo': self.object}  # ❌ 기본 컨텍스트가 사라짐
    return context
  • 이 경우 Django의 기본 컨텍스트 변수(object, view 등)가 포함되지 않습니다.
  • 따라서 템플릿에서 {{ object.title }} 또는 {{ view }}와 같은 변수를 사용할 수 없게 됩니다.

3. 템플릿에서 기본 컨텍스트 사용

📌 DetailView에서 기본 컨텍스트 사용

<h1>{{ object.title }}</h1>
<p>{{ object.description }}</p>

📌 ListView에서 기본 컨텍스트 사용

<ul>
    {% for item in object_list %}
        <li>{{ item.title }}</li>
    {% endfor %}
</ul>
  • ListView에서는 object_list가 자동으로 전달되므로, {% for item in object_list %}와 같이 사용할 수 있습니다.

📌 CreateView에서 기본 컨텍스트 사용

<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Submit</button>
</form>
  • CreateView에서는 form이 기본 컨텍스트로 제공되므로, {{ form.as_p }}와 같이 사용할 수 있습니다.

4. 결론

  • Django는 CBV의 get_context_data()에서 기본적으로 object, object_list, form 등 다양한 데이터를 컨텍스트로 제공합니다.
  • 항상 super().get_context_data()를 호출하여 기본 컨텍스트를 유지하고, 필요한 추가 데이터를 컨텍스트에 삽입하세요.

0개의 댓글

관련 채용 정보