Django에서는 함수형 view와 함께 class형 view 역시 지원한다.
이는 많이 쓰이는 것을 클래스로 만들어 두어 사용의 편의성을 높이기 위해 만들어 졌다.
module import
from django.views import View
views.py
class PostCreateView(View):
def get(self, request):
post_form = PostForm()
return render(request, 'posts/post_form.html', {'form': post_form}
def post(self, request):
post_form = PostForm(request.POST)
if post_form.is_valid():
new_post = post_form.save()
return redirect('post-detail', post_id=new_post.id)
urls.py
클래형 뷰는 함수형 뷰와 쓰는 방식이 조금 다름
.as_view()를 추가해 주어야 함
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('posts/', views.PostListView.as_view(), name='post-list'),
...
]
장고 개발자들이 자주 쓸만한 형태의 view를 하나의 형태로 만들어 둔 것
자주 사용하는 기능이 구현되어 있어, 제네릭 뷰를 상속하면 원하는 기능을 빠르게 구현할 수 있다.
from django.views.generic import CreateView
from django.urls import reverse
class PostCreateView(CreateView):
model = Post # 우리가 사용할 모델 할당
form_class = PostForm # 우리가 사용할 폼
template_name = 'posts/post_form.html' # 렌더할 템플릿
# 이동할 url
def get_success_url(self):
# kwargs = keyword argument의 약자로, 사전형으로 키워드를 이용해서 값을 전달시 사용
# self.objects.id를 통해 새로 생성된 post 데이터 객체에 접근할 수 있다.
# reverse(<이동할 url>, <context>)
return reverse('post-detail', kwargs={'post_id': self.object.id})
class PostListView(ListView):
model = Post
template_name = 'posts/post_list.html'
context_object_name = 'posts' # 넘겨줄 데이터의 이름
# 글을 최신 순으로 정렬 -> '-' 기호를 붙이면 가장 최신 순으로 정렬됨
# '-' 기호를 붙이지 않으면 오름차순으로 정렬됨
ordering = ['-dt_created']
# 몇 개 단위로 페이지를 나눌 것인지 결정
paginate_by = 6
# 현재 페이지를 쿼리 스트링의 어떤 값으로 조회하는지 알려주게 됨
page_kwarg = 'page'
{% if page_obj.object_list %}
<div class="post_container">
{% for post in page_obj.object_list %}
<div class="post">
<a href={% url 'post-detail' post.id %}>
<h2 class="title">{{post.title}}</h2>
<p class="date">{{post.dt_created}}</p>
<p class="text">{{post.content|slice:":100"}}</p>
</a>
</div>
{% endfor %}
</div>
<div class="paginator">
{% if page_obj.has_previous %}
<a href="?page=1" class="first">first</a>
<a href="?page={{ page_obj.previous_number }}" class="prev">prev</a>
{% endif %}
<span>
<p>{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</p>
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}" class="next">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}" class="last">last</a>
{% endif %}
</div>
{% else %}
urlpatterns = [
path('posts/', views.PostListView.as_view(), name='post-list'),
]
from django.views.generic import DetailView
class PostDetailView(DetailView):
model = Post
template_name = 'posts/post_detail.html'
# 특정 id에 해당하는 post를 보여줘야 함
pk_url_kwarg = 'post_id'
context_object_name = 'post'
urlpatterns = [
path('posts/<int:post_id>', views.PostDetailView.as_view(), name='post-detail'),
]
from django.views.generic import UpdateView
class PostUpdateView(UpdateView):
model = Post
form_class = PostForm()
template_name = "posts/post_form.html"
pk_url_kwarg = 'post_id'
# postform의 유효성 검증 통과시 이동할 url
def get_success_url(self):
return reverse('post-detail', kwargs={'post_id': self.object.id})
urlpatterns = [
path('posts/<int:post_id>/edit',
views.PostUpdateView.as_view(), name='post-update')
]
from django.views.generic import DeleteView
class PostDeleteView(DeleteView):
model = Post
template_name = "posts/post_confirm_delete.html"
pk_url_kwarg = 'post_id'
context_object_name = 'post'
def get_success_url(self):
return reverse('post-list')
urlpatterns = [
path('posts/<int:post_id>/delete',
views.PostDeleteView.as_view(), name='post-delete'),
]
ListView
DetailView
'context_object_name'은 view에서 template으로 전달하는 모델 데이터에 대한 이름을 저장해 준다.
👉 그런데 이를 따로 지정하지 않으면 모델명을 이용해 template으로 '<모델명>_list'로 전달하게 된다.
context_object_name = 'model_data'
{
'paginator': <Django에서 제공하는 Paginator 객체> # paginate_by를 설정해 주지 않으면 default는 None이다.
'page_obj': <Page 객체>,
'is_paginated': False,
'object_list': [데이터 목록이 담긴 QuerySet],
'<모델명>_list': [데이터 목록이 담긴 QuerySet]
}
ListView
[기존]
{% if page_obj.object_list %}
<div class="post_container">
{% for post in page_obj.object_list %}
<div class="post">
<a href={% url 'post-detail' post.id %}>
...
[바뀐 후]
{% if page_obj.object_list %}
<div class="post_container">
{% for post in object_list %} // page_obj는 지워도 된다.
<div class="post">
<a href={% url 'post-detail' post.id %}>
...
DetailView
아래와 같이 적기만 하면 된다.
class PostDetailView(DetailView):
model = Post
CreateView
class PostCreateView(CreateView):
model = Post # 우리가 사용할 모델 할당
form_class = PostForm # 우리가 사용할 폼
def get_success_url(self):
# 이동할 url
# kwargs = keyword argument의 약자로, 사전형으로 키워드를 이용해서 값을 전달시 사용
# self.objects.id를 통해 새로 생성된 post 데이터 객체에 접근할 수 있다.
return reverse('post-detail', kwargs={'pk': self.object.id})
나머지 update, delete도 유사하게 간결하게 수정할 수 있다.
⚡ DeleteView의 경우
IndexView
from django.views.generic import RedirectView
# 함수형 뷰
def index(request):
return redirect('post-list')
# 클래스형 뷰
class IndexRedirectView(RedirectView):
pattern_name = 'post-list'