[Django] widget (1) widget의 원리와 widget 만들어보기 - 실시간 글자수 표시 widget
input 태그는 type 속성에 따라 여러 모습을 보여줍니다. text 일 때는 글을 입력할 수 있도록, date 일 때는 날짜를 지정할 수 있도록, password 일 때는 비밀번호를 입력할 수 있도록 하는 등 다양한 type이 있습니다. 그리고 각 type 에 맞춰서 브라우저에서 그에 맞는 UI 를 제공합니다. 하지만 기본적인 UI 를 제공할 뿐이지 실제로 product 레벨에서는 사용하기 부족한 게 사실입니다. 몇 가지 상황에 대해서 이를 커스텀 하는 방법에 대해서 알아보도록 하겠습니다.
django widget
django에서는 widget
을 사용하여 html input 태그를 생성합니다. widget 은 model에 따라 기본으로 지정되는 default 가 존재합니다. 좀 더 구체적으로 model field 에 따라 form field 가 결정되고 form field 에 따라 Widget 이 결정됩니다.
예를 들어 비슷한 model field 인 CharField 와 TextField 는 다음과 같이 위젯에서 차이가 있기 때문에 브라우저에서도 다르게 보여지게 됩니다.
모델 필드 | 폼 필드 | 위젯 |
---|---|---|
models.CharField | forms.CharField | forms.TextInput |
models.TextField | forms.CharField | forms.Textarea |
기본 설정
여러 widget을 만들기 위해 django project 를 만들겠습니다. 그 후 core 라는 app 을 만들고 model을 만들어주었습니다.
# core/models.py
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
class University(models.Model):
name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
class Student(models.Model):
university = models.ForeignKey(University, on_delete=models.CASCADE)
date_birth = models.DateField()
residencce = models.CharField(max_length=200)
photo = models.ImageField(blank=True)
grade = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
intro = models.TextField()
대학을 의미하는 University
라는 모델과 이와 ForeignKey
로 연결되어 있는 Student
모델이 있습니다. University
은 이름을 나타내는 name field 만을 가지고 있고 Student
모델은 소속 대학, 태어날 날, 거주지, 사진, 성적, 자기소개 등의 Field 가 있습니다.
실시간 글자수 표시
첫번째로 만들어볼 widget 은 admin 페이지에서 University
을 생성할 때 그 옆에 글자수를 표시해주는 widget 입니다. 이를 위해서 기존 forms.TextInput
을 상속받은 새로운 widget 을 만들어보도록 하겠습니다.
# core/widgets.py
from django import forms
class CounterTextInput(forms.TextInput):
template_name = "widgets/counter_text.html"
CounterTextInput
widget 은 counter_text.html
을 보여주므로 이를 만들어주도록 합시다.
<!-- templates/widgets/counter_text.html -->
{% include "django/forms/widgets/input.html" %}
<span id="counter_{{widget.attrs.id}}"></span>
<script>
document.querySelector('#{{widget.attrs.id}}').addEventListener("input", function(){
document.querySelector("#counter_{{ widget.attrs.id}}").innerHTML = this.value.length + '글자';
})
</script>
django 내부적으로 존재하는 input.html
을 include 해서 input 태그를 만들어주고, javascript 를 통해 글자를 세서 span 태그에 넣어주었습니다.
다음으로는 커스텀한 widget을 form 에 적용시켜주도록 하겠습니다.
# core/forms.py
from django import forms
from .models import University, Student
from .widgets import CounterTextInput
class UniversityForm(forms.ModelForm):
class Meta:
model = University
fields = ['name']
widgets = {
'name': CounterTextInput,
}
이제 admin 에 등록시켜주면 University
을 생성할 때 글자수가 실시간으로 뜨는 걸 확인할 수 있습니다.
# core/admin.py
from django.contrib import admin
from .models import University, Student
from .forms import UniversityForm
@admin.register(University)
class CountryAmin(admin.ModelAdmin):
form = UniversityForm
@admin.register(Student)
class PostAmin(admin.ModelAdmin):
pass