장고 ClassBaseView 기반으로 crud 만들기
이번에는 장고의 클래스 뷰만 이용해서 crud_app(게시판)을 만들어 보려 한다.
아래에는 crud_app 의 조건들이다
모델 - Post
- 제목
- 내용
- 생성일
- 생성자
- 수정일
- 수정자
- 좋아요
- 사용 여부
기능
- 게시글 목록 조회
- 게시글 상세 조회
- 게시글 생성
- 게시글 수정
- 게시글 삭제
- 게시글 좋아요 *
- 좋아요는 AJAX 처리(JS - axios 라이브러리 사용)
조건
- CBV 기반의로 작성
- 게시글은 작성자만 수정, 삭제가 가능
- 게시글 좋아요는 사용자별 1번 가능
- 중복 Template include 사용
1. ListView
일단 게시글들의 리스트들이 보이는 페이지 list_page가 필요하다.
list_page는 비교적 간단하게 구현이 가능하다.
class PostListView(ListView):
model = Post
단 2줄만 써주면 끝이다. 왜, 어떻게 이게 가능한지는 상속받은 ListView를 깊숙히 들여다보면 알 수 있다.
class BaseListView(MultipleObjectMixin, View):
"""A base view for displaying a list of objects."""
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
allow_empty = self.get_allow_empty()
if not allow_empty:
# When pagination is enabled and object_list is a queryset,
# it's better to do a cheap query than to load the unpaginated
# queryset in memory.
if self.get_paginate_by(self.object_list) is not None and hasattr(self.object_list, 'exists'):
is_empty = not self.object_list.exists()
else:
is_empty = not self.object_list
if is_empty:
raise Http404(_('Empty list and “%(class_name)s.allow_empty” is False.') % {
'class_name': self.__class__.__name__,
})
context = self.get_context_data()
return self.render_to_response(context)
우리가 상속받은 ListView 안에는 이미 get 함수가 구현이 되어 있다. 그래서 ListView를 상속받기만 해도 우리가 원하는 list_page를 구현할 수가 있는 것이다. 여기서 주의깊게 볼 것은 ListView에는 post는 없고 get 함수밖에 없다는 것이다.
2. DetailView
이제 디테일 페이지로 넘어가는 로직이 필요하다. 기존의 방식대로 했다면
class PostDetailView(View):
def get(self, request, *args, **kwargs):
return render(request, 'post_detail.html')
def post(self, request, *args, **kwargs):
return redirect('crud:post_detail', kwargs['pk'])
이런 식으로 작성했을 것이다. 하지만 장고의 DetailView를 상속받으면 간단하게 작성하고 구현이 가능하다.
class PostDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
model 에는 어떤 model의 객체를 사용할 것인지를 적어준다.
template_name 에는 어떤 템플릿에서 보여줄 것인지를 적어준다.
여기서 한가지 context_object_name 을 지정해주지 않고 해당 템플릿에서 어떻게 사용해야 되는지 의문이 든다. 기본적으로 장고는 object 변수를 만들어 그 안에 해당 객체를 넣어 보내준다. 해당 템플릿에서 많은 view가 지정이 되어 있다면 각각의 context_object_name을 지정해주어 사용해주는 것이 가독성이 좋다. 위에서는 간단하게 사용하기 위해 object 변수를 이용한다.
3. CreateView
이제 글을 생성하는 페이지가 필요하다. 글 생성 또한 장고의 CreateView를 상속받으면 쉽게 구현이 가능하다.
class PostCreateView(CreateView):
model = Post
template_name = 'post_create.html'
form_class = PostForm
success_url = '/'
위의 예제에서 다른 점이 보인다. form_class 와 success_url 이다.
form_class 는 해당 템플릿에서 어떤 Form을 사용할 것인지를 적어준다. form_class 를 사용하기 전에 먼저 forms.py를 만들고 form을 만들어 주어야 한다.
success_url 은 객체가 성공적으로 저장이 된 후 어떤 페이지로 넘겨줄 것인지를 적어준다.
class PostCreateForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'article']
forms에서 모델폼을 사용한다. 모델과 필드를 지정하면 모델폼이 자동으로 폼으로 만들어 준다.
이처럼 폼을 사용하면 view에서 한가지 로직이 추가된다.
def form_valid(self, form):
instance = form.save(commit=False)
instance.writer = self.request.user
return super().form_valid(form)
instance 변수에 폼을 넣어준다. commit=False 라는 설정은 모든 필드가 정상적으로 저장이 된 후에 해당 객체를 저장하겠다는 의미이다. 중복된 DB 저장을 방지하기 위해 사용한다.
우리가 PostCreateForm 에서 작성한 내용들을 장고가 템플릿에게 전달해준다. 그래서 템플릿에서 템플릿에서 {{ form }} 을 사용이 가능하다.
4. UpdateView
이제 해당 글을 수정해주는 페이지가 필요하다. 수정하는 페이지도 장고의 UpdateView를 상속받아 쉽게 구현이 가능하다.
class PostUpdateView(UpdateView):
model = Post
template_name = 'post_update.html'
form_class = PostCreateForm
success_url = reverse_lazy('crud:post_detail')
위의 CreateView와 비슷한 느낌이다. 다만 여기서도 한가지 수정해야 할 부분이 있다. 바로 success_url이다.
UpdateView는 수정할 객체의 pk를 받아서 수정시켜준다. 그래서 수정이 성공적으로 끝나고 다른 페이지로 넘겨줄 때 해당 객체의 pk를 같이 넘겨주어야 한다. pk를 같이 넘겨주려면 get_success_url 함수를 이용해야 한다.
def get_success_url(self):
return reverse('crud:post_detail', kwargs={'pk': self.object.pk})
5. DelateView
이제 해당 글을 삭제시켜주는 기능이 필요하다. 삭제 기능도 장고의 DeleteView를 상속받아 쉽게 구현이 가능하다.
class PostDeleteView(DeleteView):
model = Post
context_object_name = 'target_post'
template_name = 'post_detail.html'
success_url = reverse_lazy('crud:post_list')
다음 글에서는 Djgnao와 axios를 이용해 좋아요 기능을 구현한 내용을 포스팅 할 것이다.
'django' 카테고리의 다른 글
Django ORM (0) | 2022.03.09 |
---|---|
Django와 Axios를 이용한 좋아요 구현하기 (0) | 2022.01.15 |
Django 프로젝트 구조 (0) | 2021.12.07 |
Django Deploy (0) | 2021.12.07 |
Django - docker (0) | 2021.12.07 |