반응형

Django 개발시 새로운 데이터를 생성하는 기능을 자주 구현하게 된다. 예를 들어 블로그 포스트 작성, 사용자 등록, 댓글 작성 등이 있다. Django는 이런 생성 로직을 쉽게 구현할 수 있도록 CreateView라는 제너릭 뷰를 제공한다.

 

CreateView란?

CreateView는 Django의 클래스 기반 뷰(CBV) 중 하나로, 새로운 객체를 생성하기 위한 폼을 표시하고 제출된 데이터를 처리하는 뷰이다. 함수 기반 뷰(FBV)로 직접 구현하면 꽤 많은 코드가 필요한 기능들을 CreateView는 손쉽게 제공한다.

 

1. 기본 설정하기

CreateView를 사용하기 위한 가장 기본적인 설정은 다음과 같다:

from django.views.generic.edit import CreateView
from .models import MyModel

class MyCreateView(CreateView):
    model = MyModel
    fields = ['field1', 'field2']  # 입력받을 필드들
    template_name = 'myapp/create.html'  # 사용할 템플릿
    success_url = '/success/'  # 생성 성공 후 리다이렉트할 URL

Django의 generic view인 CreateView 클래스를 import해오고, 이를 상속받아 새로운 커스텀 뷰를 만든다. 이렇게 만든 클래스는 CRUD 중 Create 기능을 담당한다.

각 필드의 설명은 아래와 같다:

  • model: 어떤 모델의 객체를 생성할지 지정한다. 여기서는 MyModel 모델의 인스턴스가 생성되게 된다.
  • fields: 폼에서 입력받을 필드들을 지정한다. 사용자에게 이 필드들만 입력받아 객체를 생성한다. 모델의 모든 필드가 아닌 필요한 필드만 지정할 수 있다.
  • template_name: 입력 폼을 보여줄 템플릿 파일을 지정한다. 이 템플릿에서 {{ form }}을 사용하면 자동으로 폼이 생성된다.
  • success_url: 객체 생성이 성공했을 때 리다이렉트할 URL을 지정한다. 

이처럼 필드 지정만으로, 폼 처리, 유효성 검사, 객체 저장 등의 일반적인 작업이 자동으로 처리된다. 즉, 최소한의 코드로 생성 기능을 구현할 수 있다.

 

2. HTTP 메서드별 동작 방식

GET 요청 시:

  • CreateView는 지정된 model을 기반으로 빈 ModelForm을 생성한다.
  • 이 폼을 템플릿에 전달하여 사용자에게 입력 폼을 보여준다.
  • 템플릿에서는 {{ form }}으로 접근할 수 있다.

POST 요청 시:

  • 사용자가 제출한 데이터의 유효성을 검사한다.
  • 폼에 입력된 내용이 유효한(valid) 경우: 새로운 객체를 생성하고 success_url로 리다이렉트한다
  • 폼에 입력된 내용이 유효하지 않은(invalid) 경우: 에러 메시지와 함께 폼을 다시 보여준다.

 

3. 실제 사용 예시 

# urls.py
path('create/', MyCreateView.as_view(), name='create')

# create.html
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">저장</button>
</form>

 

4. 주요 커스터마이징 포인트 

CreateView는 다양한 메서드를 오버라이드하여 동작을 커스터마이징할 수 있다. 몇가지 예시를 만들어봤다:

  • form_valid(self, form): 폼 데이터가 유효할 때 실행되는 메서드
  • get_success_url(self): 성공 시 리다이렉트할 URL을 동적으로 지정
  • get_form_class(self): 사용할 폼 클래스를 커스텀하게 지정
  • get_initial(self): 폼의 초기값을 설정
  • get_form_kwargs(self): 폼 인스턴스를 생성할 때 전달될 키워드 인자들을 결정

 

from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .models import MyModel
from .forms import MyCustomForm  # 커스텀 폼 클래스
from django.contrib import messages  # 메시지 프레임워크

class MyCreateView(CreateView):
    model = MyModel
    fields = ['field1', 'field2']
    template_name = 'myapp/create.html'
    
    def form_valid(self, form):
        """폼이 유효할 때 실행되는 메서드"""
        # 저장하기 전에 현재 로그인한 사용자를 작성자로 지정
        form.instance.author = self.request.user
        
        # 추가적인 데이터 처리
        form.instance.status = 'draft'
        
        # 부모 클래스의 form_valid 호출 (실제 저장 발생)
        response = super().form_valid(form)
        
        # 성공 메시지 추가
        messages.success(self.request, '성공적으로 생성되었습니다!')
        
        return response

    def get_success_url(self):
        """성공 시 이동할 URL을 동적으로 반환"""
        # 새로 생성된 객체의 detail 페이지로 이동
        return reverse_lazy('myapp:detail', kwargs={'pk': self.object.pk})
        
        # 또는 사용자 타입에 따라 다른 페이지로 이동
        if self.request.user.is_staff:
            return reverse_lazy('myapp:admin_list')
        return reverse_lazy('myapp:user_list')

    def get_form_class(self):
        """사용할 폼 클래스를 결정"""
        # 조건에 따라 다른 폼 클래스 반환
        if self.request.user.is_staff:
            return MyCustomForm  # 관리자용 커스텀 폼
        return super().get_form_class()  # 기본 모델폼

    def get_initial(self):
        """폼의 초기값을 설정"""
        initial = super().get_initial()  # 기본 초기값
        
        # 현재 시간을 created_at 필드의 초기값으로 설정
        initial['created_at'] = timezone.now()
        
        # 현재 로그인한 사용자 정보로 초기값 설정
        initial['author_name'] = self.request.user.get_full_name()
        
        # URL 파라미터에서 카테고리 값을 가져와서 설정
        initial['category'] = self.request.GET.get('category', '')
        
        return initial
        
    def get_form_kwargs(self):
        """폼 생성 시 전달할 키워드 인자들을 반환"""
        # 기본 kwargs 가져오기 (부모 클래스의 처리 결과)
        kwargs = super().get_form_kwargs()

        # 현재 로그인한 사용자 전달
        kwargs['user'] = self.request.user

        # 추가 컨텍스트 전달
        kwargs['category'] = self.request.GET.get('category', 'general')
        
        # request 객체 전달
        kwargs['request'] = self.request

        return kwargs

각 메서드의 설명:

  1. form_valid(self, form):
    • 폼 데이터가 유효할 때 실행된다.
    • 객체를 저장하기 전에 추가적인 데이터 처리가 가능하다.
    • 현재 로그인한 사용자를 작성자로 지정하는 등의 작업을 수행할 수 있다.
    • messages 프레임워크를 사용해 사용자에게 알림을 보낼 수 있다.
  2. get_success_url(self):
    • 객체 생성 성공 후 리다이렉트할 URL을 동적으로 결정한다.
    • 새로 생성된 객체의 정보를 사용할 수 있다(self.object로 접근).
    • 사용자 권한 등에 따라 다른 페이지로 보낼 수 있다.
  3. get_form_class(self):
    • 사용할 폼 클래스를 동적으로 결정한다.
    • 사용자 권한이나 조건에 따라 다른 폼을 사용할 수 있다.
    • 기본 모델폼 대신 커스텀 폼을 사용할 수 있다.
  4. get_initial(self):
    • 폼의 초기값을 설정한다.
    • 현재 시간, 사용자 정보 등을 기본값으로 설정할 수 있다.
    • URL 파라미터에서 값을 가져와서 초기값으로 설정할 수 있다.
    • 부모 클래스의 initial 값을 상속받아 확장할 수 있다.
  5. get_form_kwargs(self):
    • 폼 인스턴스를 생성할 때 전달될 키워드 인자들을 결정한다.
    • 사용자 정보를 전달할 수 있다.
    • URL 파라미터에서 값을 전달할 수 있다.
    • 추가 컨텍스트를 전달할 수 있다.
    • 외부 데이터를 전달 할 수 있다.
    • 전달한 kwargs를 사용하기 위해서는 아래와 같은 커스텀 폼 클래스가 필요하다:
from django import forms
from .models import MyModel

class MyCustomForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ['field1', 'field2']

    def __init__(self, *args, **kwargs):
        # kwargs에서 추가 데이터 추출
        self.user = kwargs.pop('user', None)
        self.category = kwargs.pop('category', None)
        self.request = kwargs.pop('request', None)

        # 부모 클래스의 __init__ 호출
        super().__init__(*args, **kwargs)

        # 추가 데이터를 기반으로 폼 필드 커스터마이징
        if self.user and not self.user.is_staff:
            self.fields['field1'].widget.attrs['readonly'] = True

        if self.category == 'notice':
            self.fields['field1'].label = '공지사항 제목'

 

정리

CreateView는 객체 생성과 관련된 코드 작성을 크게 줄여준다. fields를 사용한 간단한 구현부터 form_class를 사용한 복잡한 커스터마이징까지, 상황에 맞는 적절한 방법을 선택할 수 있다.

CreateView를 효과적으로 사용하기 위해서는 아래 규칙들을 잘 지키는 것이 좋다:

  1. 모델과 필드를 명확히 정의하기
  2. 필요한 경우 커스텀 폼 클래스 생성하기
  3. 적절한 유효성 검사 규칙 추가하기
  4. 사용자 경험을 고려한 템플릿 디자인하기
  5. 성공/실패 시의 동작 정의하기
반응형

+ Recent posts