Виджет MultiWidget
Виджет MultiWidget применяется в формах Django для создания составных полей ввода, которые состоят из нескольких независимых подвиджетов. Этот класс полезен, когда необходимо объединить несколько связанных данных в одном поле, например, дату и время, или диапазон чисел. Виджет наследует от Widget и переопределяет методы для рендеринга и обработки данных из нескольких источников.
Синтаксис
from django.forms import MultiWidget
class CustomMultiWidget(MultiWidget):
def __init__(self, attrs=None):
widgets = [
SomeWidget(attrs=attrs),
AnotherWidget(attrs=attrs),
]
super().__init__(widgets, attrs=attrs)
def decompress(self, value):
"""
Разбивает составное значение на список значений для каждого виджета.
"""
if value:
return [value.part1, value.part2]
return [None, None]
Основные компоненты виджета:
-
конструктор
__init__принимает список виджетов, которые будут объединены -
метод
decompressпреобразует единое значение в список значений для подвиджетов -
метод
renderотвечает за отображение всех подвиджетов -
метод
value_from_datadictсобирает данные из всех подвиджетов в единое значение
Пример
Создадим виджет для ввода диапазона цен, состоящий из двух полей: минимальная и максимальная цена:
from django.forms import MultiWidget, NumberInput
class PriceRangeWidget(MultiWidget):
def __init__(self, attrs=None):
widgets = [
NumberInput(attrs={'placeholder': 'Min', **attrs}),
NumberInput(attrs={'placeholder': 'Max', **attrs}),
]
super().__init__(widgets, attrs=attrs)
def decompress(self, value):
if value:
return [value.min_price, value.max_price]
return [None, None]
Пример
Используем созданный виджет в форме для ввода диапазона цен:
from django import forms
from django.core.validators import MinValueValidator
class PriceRangeForm(forms.Form):
price_range = forms.CharField(
widget=PriceRangeWidget(attrs={'class': 'price-input'}),
required=False,
label='Price range'
)
def clean_price_range(self):
data = self.cleaned_data['price_range']
if data:
min_val, max_val = data.split(',')
min_val = int(min_val)
max_val = int(max_val)
if min_val > max_val:
raise forms.ValidationError("Min price cannot be greater than max price")
return {'min': min_val, 'max': max_val}
return None
Результат рендеринга формы:
<form method="post">
<div class="field-wrapper">
<label for="id_price_range">Price range:</label>
<input type="number" name="price_range_0" placeholder="Min" class="price-input" id="id_price_range_0">
<input type="number" name="price_range_1" placeholder="Max" class="price-input" id="id_price_range_1">
</div>
<button type="submit">Submit</button>
</form>
Пример
Создадим виджет для ввода времени в формате "часы:минуты" с использованием выпадающих списков:
from django.forms import MultiWidget, Select
class TimePickerWidget(MultiWidget):
def __init__(self, attrs=None):
hours = [(str(i), f"{i:02d}") for i in range(24)]
minutes = [(str(i), f"{i:02d}") for i in range(60)]
widgets = [
Select(choices=hours, attrs=attrs),
Select(choices=minutes, attrs=attrs),
]
super().__init__(widgets, attrs=attrs)
def decompress(self, value):
if value:
return value.split(':')
return [None, None]
Используем виджет для выбора времени в форме:
from django import forms
class AppointmentForm(forms.Form):
appointment_time = forms.CharField(
widget=TimePickerWidget(attrs={'class': 'time-select'}),
label='Appointment time',
help_text='Select hours and minutes'
)
def clean_appointment_time(self):
data = self.cleaned_data['appointment_time']
if data:
hours, minutes = data.split(',')
return f"{int(hours):02d}:{int(minutes):02d}"
return None
Результат выполнения кода при отправке формы:
"Appointment time: 14:30"
Пример
Создадим составной виджет для ввода полного имени, состоящий из полей для имени и фамилии:
from django.forms import MultiWidget, TextInput
class FullNameWidget(MultiWidget):
def __init__(self, attrs=None):
widgets = [
TextInput(attrs={'placeholder': 'First name', **attrs}),
TextInput(attrs={'placeholder': 'Last name', **attrs}),
]
super().__init__(widgets, attrs=attrs)
def decompress(self, value):
if value:
return value.split(' ')
return ['', '']
Используем виджет в форме для регистрации пользователя:
from django import forms
class UserRegistrationForm(forms.Form):
full_name = forms.CharField(
widget=FullNameWidget(attrs={'class': 'name-field'}),
label='Full name',
required=True
)
def clean_full_name(self):
data = self.cleaned_data['full_name']
if data:
first, last = data.split(',')
return f"{first.strip()} {last.strip()}"
return None
Результат обработки данных формы:
"Full name: John Doe"
Смотрите также
-
виджет
SplitDateTimeWidget,
который разделяет ввод даты и времени на два отдельных поля -
виджет
SelectDateWidget,
который использует выпадающие списки для выбора даты -
поле
MultiValueField,
которое используется вместе с MultiWidget для валидации составных данных -
виджет
TextInput,
стандартный виджет для ввода текста, используемый в составных виджетах