Class Based View
장점
단점
path('about/', TemplateView.as_view(template_name='about.html'), name='about'),
# 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')), 별로
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'),
- ListView는 기본적으로 템플릿으로 아래의 context 변수를 전달합니다:
• page_obj: 현재 페이지와 관련된 정보를 포함하는 Page 객체.
• paginator: 전체 페이지네이션을 관리하는 Paginator 객체.
• object_list: 현재 페이지의 객체 리스트.
# 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 기본적으로 템플릿으로 아래의 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
# 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'),
]
- DetailView 기본적으로 템플릿으로 아래의 context 변수를 전달합니다:
• form: 지정한 fields에 해당하는 것을 불러옵니다. {{ form.as_p }}
• view {{ view.model }} 또는{{ view.__class__.__name__ }}
를 통해 뷰와 관련된 정보를 출력할 수 있습니다.
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'),
]
- 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'),
]
- DetailView 기본적으로 템플릿으로 아래의 context 변수를 전달합니다:
• 모델 이름을 불러 올 수 있습니다. Blog 라면 blog
• object: 설정한 모델을 불러올 수 있습니다. {{ object.title }}
• get_context_data 메서드를 오버라이드 하여 컨텍스트에 데이터를 추가 할 수 있습니다.
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'),
]
개발자들은 반복적인 것을 싫어해서 반복을 줄이려고 노력함
앞부분을 지정해놓으면 앞부분을 사용하지 않고 뒷부분만 사용해서 되게하는 것path('accounts/', include("django.contrib.auth.urls")),
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')
def get_context_data(self, **kwargs):
context = {'todo': self.object.__dict__}
return context
get_context_data()
기본 컨텍스트Django의 DetailView
, ListView
, CreateView
, UpdateView
같은 CBV(Class-Based View)는 자동으로 특정 기본 컨텍스트를 제공합니다.
이 컨텍스트는 템플릿에서 데이터를 쉽게 사용할 수 있도록 돕습니다.
DetailView
개별 객체를 조회할 때 사용합니다.
기본 컨텍스트:
키 (context 내부 값) | 설명 |
---|---|
object | 현재 조회 중인 모델 객체 (self.object ) |
view | 현재 실행 중인 뷰 클래스 (self ) |
kwargs | URL 패턴에서 전달된 인자 (예: pk , slug ) |
ListView
모델의 객체 리스트를 조회할 때 사용합니다.
기본 컨텍스트:
키 (context 내부 값) | 설명 |
---|---|
object_list | 현재 모델의 전체 리스트 (QuerySet) |
view | 현재 실행 중인 뷰 클래스 (self ) |
paginator | ListView 에서 페이징을 사용할 경우 Paginator 객체 |
page_obj | 현재 페이징된 페이지 정보 |
CreateView
, UpdateView
, DeleteView
객체를 생성, 업데이트, 삭제할 때 사용합니다.
기본 컨텍스트:
키 (context 내부 값) | 설명 |
---|---|
form | 현재 뷰에서 사용되는 ModelForm 객체 |
object | UpdateView , DeleteView 에서 수정/삭제 대상 객체 |
view | 현재 실행 중인 뷰 클래스 (self ) |
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
object
, view
등)가 포함되지 않습니다.{{ object.title }}
또는 {{ view }}
와 같은 변수를 사용할 수 없게 됩니다.DetailView
에서 기본 컨텍스트 사용<h1>{{ object.title }}</h1>
<p>{{ object.description }}</p>
ListView
에서 기본 컨텍스트 사용<ul>
{% for item in object_list %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
CreateView
에서 기본 컨텍스트 사용<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
CreateView
에서는 form
이 기본 컨텍스트로 제공되므로, {{ form.as_p }}
와 같이 사용할 수 있습니다.get_context_data()
에서 기본적으로 object
, object_list
, form
등 다양한 데이터를 컨텍스트로 제공합니다.super().get_context_data()
를 호출하여 기본 컨텍스트를 유지하고, 필요한 추가 데이터를 컨텍스트에 삽입하세요.