Виджеты

Виджет – это представление поля в виде HTML кода. Виджеты обеспечивают генерацию HTML и извлечение соответствующих данных из GET/POST запросов.

Назначение виджета

При добавлении поля на форму, Django использует стандартный виджет, наиболее подходящий к отображаемому типу данных. Для того, чтобы узнать какой виджет использует интересующий вас тип поля обратитесь к Классы встроенных полей.

Тем не менее, если потребуется указать другой виджет для поля, просто используйте аргумент widget при определении поля. Например:

from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)

Этот код создают форму, у которой полю комментария назначен виджет class:Textarea вместо стандартного TextInput widget.

Аргументы виджетов

Большинство виджетов принимает дополнительные аргументы. Они могут быть назначены при определении виджета для поля. В следующем примере атрибут years передаётся в SelectDateWidget:

from django.forms.fields import DateField, ChoiceField, MultipleChoiceField
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.forms.extras.widgets import SelectDateWidget

BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'))
FAVORITE_COLORS_CHOICES = (('blue', 'Blue'),
                            ('green', 'Green'),
                            ('black', 'Black'))

class SimpleForm(forms.Form):
    birth_year = DateField(widget=SelectDateWidget(years=BIRTH_YEAR_CHOICES))
    gender = ChoiceField(widget=RadioSelect, choices=GENDER_CHOICES)
    favorite_colors = forms.MultipleChoiceField(required=False,
        widget=CheckboxSelectMultiple, choices=FAVORITE_COLORS_CHOICES)

Обратитесь к Встроенные виджеты для получения подробной информации о доступных виджетах и аргументах, которые они принимают.

Виджеты, унаследованные от виджета Select

Виджеты, унаследованные от виджета Select, предназначены для работы с вариантами. Они предоставляют список вариантов, из которых надо сделать выбор. Разные виджеты позволяют сделать выбор по-разному. Базовый виджет Select использует HTML таг <select>, а унаследованный виджет RadioSelect использует радио кнопки.

Виджеты типа Select по умолчанию используют поля ChoiceField. Варианты, отображаемые виджетом, наследуются от ChoiceField и изменение ChoiceField.choices повлияет на Select.choices. Например:

>>> from django import forms
>>> CHOICES = (('1', 'First',), ('2', 'Second',)))
>>> choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
>>> choice_field.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices = ()
>>> choice_field.choices = (('1', 'First and only',),)
>>> choice_field.widget.choices
[('1', 'First and only')]

Виджеты, поддерживающие атрибут choices могут, тем не менее, использоваться совместно с полями, которые не основаны на выборе, – такими как CharField – но рекомендуется использовать поля типа ChoiceField в случаях, когда варианты берутся из модели.

Настройка экземпляров виджета

При отображении виджета на странице сайта, Django генерирует минимальный HTML код, который не включает в себя указание классов или других специфических атрибутов виджета. Это означает, что все виджеты типа TextInput будут отображаться на странице однообразно.

Если требуется визуально выделить один виджет от других, потребуется указать для него дополнительные атрибуты. Предоставленные вами атрибуты будут добавлены в результирующий HTML код виджета.

Например, рассмотрим следующую простую форму:

from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()

Эта форма включает в себя три обычных виджета TextInput, которым не назначены ни CSS класс, ни дополнительные атрибуты. Это означает, что визуально они будут выглядеть одинаково:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>

На реальной странице сайта, возможно, вам понадобится разнообразить их отображение. Вам может потребоваться сделать поле для ввода комментария побольше или назначить имя виджету, чтобы он начал реагировать на CSS класс. Для этого надо испольховать аргумент Widget.attrs при создании виджета:

Например:

class CommentForm(forms.Form):
    name = forms.CharField(
                widget=forms.TextInput(attrs={'class':'special'}))
    url = forms.URLField()
    comment = forms.CharField(
               widget=forms.TextInput(attrs={'size':'40'}))

Djando добавить дополнительные атрибуты в генерируемый HTML код:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>

Встроенные виджеты

Django предоставляет все основные HTML виджеты и ещё некоторые часто используемые группы виджетов:

Widget

class Widget

Абстрактный класс не может быть использован для отображения поля, но он предоставляет основной атрибут attrs.

attrs

Словарь, которые содержит HTML атрибуты, которые будут назначены сгенерированному виджету.

>>> name = forms.TextInput(attrs={'size': 10, 'title': 'Your name',})
>>> name.render('name', 'A name')
u'<input title="Your name" type="text" name="name" value="A name" size="10" />'

TextInput

class TextInput

Ввод текста: <input type='text' ...>

PasswordInput

class PasswordInput

Ввод пароля: <input type='password' ...>

Принимает один необязательный аргумент:

render_value

Определеяет, надо ли заполнять этот виджет при повторном отображении формы при ошибке (по умолчанию False).

Изменено в Django 1.3: The default value for render_value was changed from True to False

HiddenInput

class HiddenInput

Скрытый ввод: <input type='hidden' ...>

MultipleHiddenInput

class MultipleHiddenInput

Множество виджетов``<input type=’hidden’ ...>``.

Виджет, который обрабатывает множество скрытых виджетов для полей, которые содержат список значений.

choices

Этот атрибут является необязательным, если поле не имеет атрибут choices. В противном случае, его содержимое имеет преимущество над атрибутами Field.

FileInput

class FileInput

Загрузка файла: <input type='file' ...>

ClearableFileInput

class ClearableFileInput

Загрузка файла: <input type='file' ...>, с дополнительным чекбоксом для очистки значения поля, если оно не является обязательным и имеет начальные данные.

DateInput

class DateInput

Ввод даты в простое текстовое поле: <input type='text' ...>

Принимает один необязательный аргумент:

format

Формат, в котором отображается начальное значение поля.

Если аргумент format не предоставлен, то стандартный формат берётся из DATE_INPUT_FORMATS с учётом Формат локализации.

DateTimeInput

class DateTimeInput

Ввод даты/времени в простое текстовое поле: <input type='text' ...>

Принимает один необязательный аргумент:

format

Формат, в котором отображается начальное значение поля.

Если аргумент format не предоставлен, то стандартный формат берётся из DATETIME_INPUT_FORMATS с учётом Формат локализации.

TimeInput

class TimeInput

Ввод времени в простое текстовое поле: <input type='text' ...>

Принимает один необязательный аргумент:

format

Формат, в котором отображается начальное значение поля.

Если аргумент format не предоставлен, то стандартный формат берётся из TIME_INPUT_FORMATS с учётом Формат локализации.

Textarea

class Textarea

Текстовая область: <textarea>...</textarea>

CheckboxInput

class CheckboxInput

Чекбокс: <input type='checkbox' ...>

Принимает один необязательный аргумент:

check_test

Функция, которая принимает значение элемента и возвращает True, если указанное значение было отмечено на элементе.

Select

class Select

Виджет выбора: <select><option ...>...</select>

choices

Этот атрибут является необязательным, если поле не имеет атрибут choices. В противном случае, его содержимое имеет преимущество над атрибутами Field.

NullBooleanSelect

class NullBooleanSelect

Виджет выбора с вариантами ‘Неизвестно’, ‘Да’ и ‘Нет’.

SelectMultiple

class SelectMultiple

Аналогично Select, но разрешён множественный выбор: <select multiple='multiple'>...</select>.

RadioSelect

class RadioSelect

Аналогично Select, но отображается в виде списка радио кнопок с помощью тагов <li>:

<ul>
  <li><input type='radio' ...></li>
  ...
</ul>

Для более тонкого управления процессом генерации HTML кода, вы можете выводить радио кнопки в шаблон в цикле. Рассмотрим форму myform с полем beatles, которое использует RadioSelect в качестве виджета:

{% for radio in myform.beatles %}
<div class="myradio">
    {{ radio }}
</div>
{% endfor %}

Она будет представлена в виде следующего HTML кода:

<div class="myradio">
    <label><input type="radio" name="beatles" value="john" /> John</label>
</div>
<div class="myradio">
    <label><input type="radio" name="beatles" value="paul" /> Paul</label>
</div>
<div class="myradio">
    <label><input type="radio" name="beatles" value="george" /> George</label>
</div>
<div class="myradio">
    <label><input type="radio" name="beatles" value="ringo" /> Ringo</label>
</div>

Код содержит таги <label>. Также вы можете использовать атрибуты tag и choice_label для управления отображением каждой радио кнопки. Например, этот шаблон...

{% for radio in myform.beatles %}
    <label>
        {{ radio.choice_label }}
        <span class="radio">{{ radio.tag }}</span>
    </label>
{% endfor %}

... преобразуется в следующий HTML:

<label>
    John
    <span class="radio"><input type="radio" name="beatles" value="john" /></span>
</label>
<label>
    Paul
    <span class="radio"><input type="radio" name="beatles" value="paul" /></span>
</label>
<label>
    George
    <span class="radio"><input type="radio" name="beatles" value="george" /></span>
</label>
<label>
    Ringo
    <span class="radio"><input type="radio" name="beatles" value="ringo" /></span>
</label>

Если вы просто выведите поле в шаблоне с помощью {{ myform.beatles }}, то кнопки будут выведены с помощью тага <ul> с <li>, как было показано ранее.

CheckboxSelectMultiple

class CheckboxSelectMultiple

Аналогичен SelectMultiple, но отображается в виде списка чекбоксов.

<ul>
  <li><input type='checkbox' ...></li>
  ...
</ul>

MultiWidget

class MultiWidget

Обёртка вокруг других виджетов. Возможно вам потребуется использовать этот класс совместно с MultiValueField.

Его метод render() отличается от аналогичных методов других виджетов, так как он должен реализовывать функционал отображения единственного значения в нескольких виджетах.

Подклассы иметь метод format_output, который может принимать список обработанных виджетов и возвращать HTML код, который форматирует их в нужном вам виде.

Аргумент value, используемый при генерации, может быть одним из:

  • Список (list).
  • Единственное значение (т.е., строка), которая является “сжатым” представлением списка значений.

Во втором случае, т.е. когда значение не является списом, render() сначала преобразует значение в список, а затем обрабатывает его. Преобразование производится с помощью метода decompress(), который должен быть реализован в потомках MultiWidget. Этот метод принимает одно “сжато” значение и возвращает список. Пример этому – как SplitDateTimeWidget преобразует datetime значение в список, состоящий из значений даты и времени:

class SplitDateTimeWidget(MultiWidget):

    # ...

    def decompress(self, value):
        if value:
            return [value.date(), value.time().replace(microsecond=0)]
        return [None, None]

При работе метода render() каждому значени. в списке назначается соответствующий виджет. Первое значение значение назначается первому виджету, второе – второму и так далее.

Класс MultiWidget имеет один обязательный аргумент:

widgets

Итератор, содержащий необходимые виджеты.

SplitDateTimeWidget

class SplitDateTimeWidget

Обёртка (MultiWidget`с помощью) вокруг двух виджетов: :class:`DateInput для даты и TimeInput для времени.

SplitDateTimeWidget имеет два необязательных атрибута:

date_format

Аналогичен DateInput.format.

time_format

Аналогичен TimeInput.format.

SplitHiddenDateTimeWidget

class SplitHiddenDateTimeWidget

Аналогичен SplitDateTimeWidget, но используется HiddenInput для даты и времени.

SelectDateWidget

class SelectDateWidget

Обёртка вокруг трёх виджетов Select – месяц, день и год. Следует отметить, что этот виджет располагается отдельно от стандартных виджетов.

Принимает один необязательный аргумент:

years

Необязательный список/кортеж с вариантами года. По умолчанию содержит текущий год и девять последующих.