오히려 좋아..

상황이 나쁘게만 흘러가는 것 같을 때 외쳐보자.. .

궁금한 마음으로 포트폴리오 보기

Web Programming/Django

[Django] Form 동적으로 생성하기

junha6316 2021. 3. 27. 16:53

현재 하고 있는 프로젝트의 요구 사항중에 admin에서 몇가지 설정을 통해 이벤트 랜딩페이지를 생성하는 부분이 있었다.

 

이벤트마다 수집하는 개인정보가 달랐기 때문에 수집 개인정보 항목(이름, 전화번호..등등)을 이벤트와 ManyToMany로 연결시켜서

이벤트마다 수집 개인정보 항목을 다르게 수집할 수 있도록 만들어 주었다. 

 

일단 기한안에 완성해야했기 때문에 view에 모든 부분을 구현하고 배포한뒤 코드를 보니 개인정보를 받는 view나 django template 쪽의 코드가 지나치게 지저분해졌다.

 

이를 리팩토링하기 위해 form을 사용해서 이벤트마다 동적으로 폼을 생성할 수 있도록 만들어 주기로 했다.

이번 포스트에서는 정적인 form이 아닌 모델 마다 변하는 동적인 폼을 생성하는 방법에 대해 알아보도록 하겠다.

 

위에 보이는 개인정보 항목이 이벤트마다 달라진다.

1. 구현

처음 부터 끝까지 설명 할 수는 없지만 핵심 아이디어는 EventForm의 생성자에서 self.field에 항목을 추가시켜주면 된다는 것이다. 

#registrations/forms.py

from events.models import Event
from participants.models import Participant


def get_proper_field(field_name, field_label):

	""" 필드 이름을 기준으로 적절한 forms.Field 클래스를 반환해준다. """
    
    if field_name == "email":
        return forms.EmailField(label=field_label, required=True)
    else:
        return forms.CharField(label=field_label, required=True)

class EventForm(forms.Form):

    def __init__(self, event, *args, **kwargs): #인자로 event Object를 받아준다.
    
        """ Form 클래스의 생성자 """
        
        super().__init__(*args, **kwargs) #먼저 부모 클래스인 Form 클래스를 실행시켜주고
        self.event = event 
        self.items = event.collectedVisitorInfoItems.all().order_by("number") 
        # 해당 이벤트가 수집해야하는 개인정보 항목들을 갖고 온다
        
        for item in self.items: #for문을 돌면서
            field_name =item.name #수집하는 항목의 필드
            field_label = item.label # 레이블
            self.fields[field_name] = get_proper_field(name, label)
    		#EventForm class에 field class를 저장시켜준다.
            
    def save(self):
    	#저장하는 것도 오버라이드 해준다.
        email = self.cleaned_data["email"] 
        participant, created = Participant.objects.get_or_create(email=email, attendEvent=self.event)
		#이메일과 이벤트 기준으로 해당 이벤트 참가자가 있으면 정보를 수정해주고 없으면 새로 생성 시켜준다.
        for name, value in self.cleaned_data.items(): #수집정보항목를 돌면서
            setattr(participant, name, value)
        participant.save()
        return
    

 

2. 잡생각

Two scoops of Django(애칭:장고 두숟갈) 에서 이런 내용이 있다.

view의 코드를 최대한 줄이고 model과 form에 비즈니스 로직을 구현해라.

프로젝트의 첫배포를 마치고 뭔가 이제 뭘해야될지 몰랐는데 좋은 리팩토링 아이디어가 되는 것 같다.

 

아래 포스트에서 도움을 많이 받았다.

www.caktusgroup.com/blog/2018/05/07/creating-dynamic-forms-django/