본문 바로가기

django

Django CBV 기반 CRUD 만들기

장고 ClassBaseView 기반으로 crud 만들기

이번에는 장고의 클래스 뷰만 이용해서 crud_app(게시판)을 만들어 보려 한다.

아래에는 crud_app 의 조건들이다

모델 - Post

  • 제목
  • 내용
  • 생성일
  • 생성자
  • 수정일
  • 수정자
  • 좋아요
  • 사용 여부

기능

  1. 게시글 목록 조회
  2. 게시글 상세 조회
  3. 게시글 생성
  4. 게시글 수정
  5. 게시글 삭제
  6. 게시글 좋아요 *

조건

  1. CBV 기반의로 작성
  2. 게시글은 작성자만 수정, 삭제가 가능
  3. 게시글 좋아요는 사용자별 1번 가능
  4. 중복 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