Виджет RadioSelect

Виджет RadioSelect предназначен для отображения выбора одного варианта из нескольких в виде списка радио-кнопок. Он используется с полями выбора, такими как ChoiceField, ModelChoiceField или TypedChoiceField. По умолчанию Django отображает выбор с помощью виджета Select, но RadioSelect дает более наглядный интерфейс, особенно когда вариантов немного и нужно сразу видеть все доступные опции.

Виджет поддерживает настройку отображения с помощью атрибутов attrs, а также позволяет кастомизировать HTML-разметку каждой радио-кнопки и её подписи через параметр choice_label или шаблоны. По умолчанию радио-кнопки выводятся вертикально, но это поведение можно изменить с помощью CSS или переопределением шаблона виджета.

Синтаксис

pythonfrom django import forms

class MyForm(forms.Form):
  field_name = forms.ChoiceField(
    choices=CHOICES,
    widget=forms.RadioSelect
  )

Пример . С ChoiceField

Создадим форму с выбором статуса заказа с помощью радио-кнопок:

pythonfrom django import forms

class OrderForm(forms.Form):
  STATUS_CHOICES = [
    ('pending', 'Pending'),
    ('processing', 'Processing'),
    ('completed', 'Completed'),
    ('cancelled', 'Cancelled'),
  ]

  status = forms.ChoiceField(
    choices=STATUS_CHOICES,
    widget=forms.RadioSelect,
    initial='pending'
  )

Результат вывода формы в шаблоне:

html<ul id="id_status">
  <li>
    <label for="id_status_0">
      <input type="radio" name="status" value="pending" id="id_status_0" checked>
      Pending
    </label>
  </li>
  <li>
    <label for="id_status_1">
      <input type="radio" name="status" value="processing" id="id_status_1">
      Processing
    </label>
  </li>
  <li>
    <label for="id_status_2">
      <input type="radio" name="status" value="completed" id="id_status_2">
      Completed
    </label>
  </li>
  <li>
    <label for="id_status_3">
      <input type="radio" name="status" value="cancelled" id="id_status_3">
      Cancelled
    </label>
  </li>
</ul>

Пример . С ModelChoiceField

Используем RadioSelect для выбора категории из модели в форме редактирования статьи:

pythonfrom django import forms
from myapp.models import Category, Article

class ArticleForm(forms.ModelForm):
  category = forms.ModelChoiceField(
    queryset=Category.objects.all(),
    widget=forms.RadioSelect,
    empty_label=None
  )

  class Meta:
    model = Article
    fields = ['title', 'content', 'category']

В контроллере создаем форму и передаем в шаблон:

pythonfrom django.shortcuts import render
from myapp.forms import ArticleForm

def create_article(request):
  form = ArticleForm()
  return render(request, 'article_form.html', {'form': form})

В шаблоне выводим форму:

html<form method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Save</button>
</form>

Настройка атрибутов

Добавим CSS-классы и атрибуты к радио-кнопкам через параметр attrs:

pythonfrom django import forms

class SurveyForm(forms.Form):
  RATING_CHOICES = [
    (1, 'Very Bad'),
    (2, 'Bad'),
    (3, 'Normal'),
    (4, 'Good'),
    (5, 'Very Good'),
  ]

  rating = forms.ChoiceField(
    choices=RATING_CHOICES,
    widget=forms.RadioSelect(
      attrs={
        'class': 'rating-radio',
        'data-type': 'survey'
      }
    ),
    initial=3
  )

В результате каждая радио-кнопка получит атрибуты:

html<input type="radio" name="rating" value="3" id="id_rating_2"
     class="rating-radio" data-type="survey" checked>

Кастомизация отображения

Для более гибкой настройки вы можете переопределить шаблон виджета. Создадим форму с выбором дня недели и кастомизируем разметку через параметр choice_label:

pythonfrom django import forms

class ScheduleForm(forms.Form):
  DAY_CHOICES = [
    ('mon', 'Monday'),
    ('tue', 'Tuesday'),
    ('wed', 'Wednesday'),
    ('thu', 'Thursday'),
    ('fri', 'Friday'),
  ]

  day = forms.ChoiceField(
    choices=DAY_CHOICES,
    widget=forms.RadioSelect,
    initial='mon'
  )

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.fields['day'].widget.choice_label = lambda choice: f"<span class='day-label'>{choice[1]}</span>"

В контроллере проверим работу формы:

pythonfrom django.shortcuts import render
from myapp.forms import ScheduleForm

def schedule_view(request):
  if request.method == 'POST':
    form = ScheduleForm(request.POST)
    if form.is_valid():
      print("Selected day:", form.cleaned_data['day'])
  else:
    form = ScheduleForm()

  return render(request, 'schedule.html', {'form': form})

Результат вывода в консоль при отправке формы:

python"Selected day: wed"

Вертикальное и горизонтальное отображение

По умолчанию RadioSelect выводит варианты вертикально. Чтобы сделать горизонтальное расположение, используйте CSS:

html<style>
  ul.radio-group {
    list-style: none;
    padding: 0;
    display: flex;
    gap: 20px;
  }
  ul.radio-group li {
    display: inline-block;
  }
</style>

{{ form.field_name }}

Либо задайте класс непосредственно в атрибутах виджета:

pythonfrom django import forms

class ColorForm(forms.Form):
  COLOR_CHOICES = [
    ('red', 'Red'),
    ('green', 'Green'),
    ('blue', 'Blue'),
  ]

  color = forms.ChoiceField(
    choices=COLOR_CHOICES,
    widget=forms.RadioSelect(
      attrs={'class': 'horizontal-radio'}
    )
  )

Смотрите также

  • виджет Select,
    который выводит выбор в виде выпадающего списка
  • виджет CheckboxSelectMultiple,
    который выводит множественный выбор в виде чекбоксов
  • виджет NullBooleanSelect,
    который выводит выбор для булевого поля с тремя состояниями
  • виджет SelectMultiple,
    который выводит множественный выбор в виде списка