Django – ModelForm field 사용자 정의 data- 속성 추가하기
Form field 가 html 로 렌더링 될 때 원하는 속성값을 부가 하고 싶은데, 장고 코드에서 자동으로 하고 싶다.
이래 저래 찾다가 코드가 발견
class CompanySelect(forms.Select):
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
option = super().create_option(name, value, label, selected, index, subindex, attrs)
if value:
option["attrs"]["data-company"] = value.instance.company_id
return option
class ProductProfileForm(forms.ModelForm):
class Meta:
model = ProductProfile
fields = ["company", "name", "product", "fwver1", "fwver2", "fwver3", "fwver4", "testset", "boxlabel", "boxpq"]
# exclude = ["order", "status", "date_done", "elapsed_time", "mode", "desc", "is_deleted", "updated_at", "created_at"]
# fields = ["order", "product", "workline", "fwver", "testset", "quantity", "date_due", "box", "boxpq", "status"]
labels = {
"company": _("*회사명"),
"product": _("상품명"),
...}
widgets = {
"company": forms.Select(attrs={"class": "form-select"}),
# "product": forms.Select(attrs={"class": "form-select flex-fill", "required": True, "style": "width: 100px;"}),
"product": CompanySelect(attrs={"class": "form-select flex-fill companyselect", "required": True}),
...
원래 그냥 forms.Select 만 쓰면 특별히 해당 필드 값을 가지고 속성을 별도로 주는 것이 어렵다. 클래스 처럼 한꺼번에 줄 수 는 있어도 해당 값에 맞는 값을 DB 에서 가져와서 넣어주는게 힘들다. 예를 들면 해당 레코드별로 있는 ID 값을 data-code 속성에 넣어주는 그런것은 하기 어렵다.
이때는 forms.Select 를 오버라이딩 해서 사용하면 된다.
CompanySelect 클래스를 참고하면 된다. 원하는 DB instance 의 값을 바로 쓸 수 있다.
아래 처럼 data-company 값이 떡 하니 적혀져서 렌더링 된다. 이값을 이용해서 코드를 작성하면 편리하게 활용할 수 있다.
<select name="form-0-product" class="form-select companyselect" required="" id="id_form-0-product">
<option value="" selected="" style="display: none;">---------</option>
<option value="200" data-company="1" style="display: none;">test1 (twareLAB)</option>
<option value="208" data-company="1" style="display: none;">test11 (twareLAB)</option>
<option value="221" data-company="1" style="display: none;">TJ100 (twareLAB)</option>
<option value="244" data-company="1" style="display: none;">TW100XR (twareLAB)</option>
<option value="222" data-company="9" style="">Product1 (WIZnet)</option>
<option value="3" data-company="9" style="">Test (WIZnet)</option>
<option value="210" data-company="10" style="display: none;">Product1-1 (TEST Company)</option>
<option value="219" data-company="10" style="display: none;">Product1-111 (TEST Company)</option>
<option value="220" data-company="10" style="display: none;">Product1-123 (TEST Company)</option>
</select>
빙에게서 받은 예제도 여기에 첨부해 둡니다.
Django의 forms.Select
위젯을 오버라이딩하는 예제를 제공해 드리겠습니다. forms.Select
위젯은 ChoiceField
의 기본 위젯으로 HTML의 <select>
요소를 생성합니다.
예를 들어, 다음과 같은 ModelForm
이 있다고 가정해봅시다.
from django import forms
from myapp.models import MyModel
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['myfield']
이 경우 myfield
가 ChoiceField
인 경우, 다음과 같이 forms.Select
위젯을 오버라이딩하여 사용자 정의 위젯을 만들 수 있습니다.
from django import forms
from myapp.models import MyModel
class MySelect(forms.Select):
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
option = super(MySelect, self).create_option(name, value, label, selected, index, subindex=subindex, attrs=attrs)
option['attrs']['data-myattribute'] = 'myvalue'
return option
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['myfield']
widgets = {
'myfield': MySelect
}
위와 같이 수정하면 myfield
필드의 <option>
요소에 data-myattribute="myvalue"
속성이 추가됩니다.
create_option
메서드는 Django의 forms.Select
위젯에서 <option>
요소를 생성하는 데 사용됩니다. 이 메서드는 다음과 같은 인수를 받습니다.
name
: 필드의 이름입니다.value
: 옵션의 값입니다.label
: 옵션의 레이블입니다.selected
: 옵션이 선택되었는지 여부를 나타내는 불리언 값입니다.index
: 옵션의 인덱스입니다.subindex
: 옵션의 하위 인덱스입니다. 기본값은None
입니다.attrs
: 옵션의 HTML 속성을 나타내는 딕셔너리입니다. 기본값은None
입니다.
create_option
메서드는 위와 같은 인수를 받아서 딕셔너리 형태의 옵션 객체를 반환합니다. 이 딕셔너리에는 다음과 같은 키가 있습니다.
name
: 필드의 이름입니다.value
: 옵션의 값입니다.label
: 옵션의 레이블입니다.selected
: 옵션이 선택되었는지 여부를 나타내는 불리언 값입니다.index
: 옵션의 인덱스입니다.attrs
: 옵션의 HTML 속성을 나타내는 딕셔너리입니다.
create_option
메서드를 오버라이딩하여 위와 같은 인수를 받고 딕셔너리 형태의 옵션 객체를 반환하는 사용자 정의 메서드를 만들 수 있습니다. 이렇게 하면 <option>
요소의 속성을 동적으로 변경할 수 있습니다.
create_option
메서드를 오버라이딩하는 예제를 더 제공해 드리겠습니다. 이전 예제에서는 create_option
메서드를 오버라이딩하여 <option>
요소에 data-myattribute="myvalue"
속성을 추가하는 방법을 보여드렸습니다.
이번에는 create_option
메서드를 오버라이딩하여 <option>
요소의 레이블을 동적으로 변경하는 방법을 보여드리겠습니다.
from django import forms
from myapp.models import MyModel
class MySelect(forms.Select):
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
option = super(MySelect, self).create_option(name, value, label, selected, index, subindex=subindex, attrs=attrs)
option['label'] = label.upper()
return option
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['myfield']
widgets = {
'myfield': MySelect
}
위와 같이 수정하면 myfield
필드의 <option>
요소의 레이블이 모두 대문자로 변경됩니다.
위젯을 오버라이딩하는 이유
Django의 위젯은 폼 필드의 HTML 표현을 담당합니다. 기본적으로 Django는 각 필드 유형에 대해 기본 위젯을 제공하지만, 때로는 이러한 기본 위젯이 원하는 요구 사항을 충족시키지 못할 수 있습니다. 이 경우 위젯을 오버라이딩하여 사용자 정의 위젯을 만들 수 있습니다.
위젯을 오버라이딩하는 이유는 다음과 같습니다.
- HTML 요소의 속성을 동적으로 변경하려는 경우
- HTML 요소의 레이아웃이나 스타일을 변경하려는 경우
- JavaScript 이벤트 핸들러를 추가하려는 경우
- 기타 사용자 정의 요구 사항을 충족시키기 위해
위와 같은 이유로 위젯을 오버라이딩하여 사용자 정의 위젯을 만들 수 있습니다.