РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
459 of 818 menu

Виджет 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,
    стандартный виджет для ввода текста, используемый в составных виджетах
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить