Настройка форм Django с помощью виджета RadioSelect
поэтому я использую jQuery UI для кожа радиокнопки но я не могу заставить Джанго сделать мою форму так, как это должно быть сделано.
мне нужна эта структура:
<table>
<tr>
<td><label for="notify_new_friends">Notify when new friends join</label></td>
<td class="radio">
<input type="radio" name="notify_new_friends" id="notify_new_friends_immediately" value="1" checked="checked"/><label for="notify_new_friends_immediately">Immediately</label>
<input type="radio" name="notify_new_friends" id="notify_new_friends_never" value="0"/><label for="notify_new_friends_never">Never</label>
</td>
</tr>
</table>
Итак, чтобы суммировать, что мне нужны переключатели в классе (радио), где у них есть input
и a label for
.
когда я представляю форму в моем шаблоне с {{ profile_form.notify_new_friends }}
Я получаю следующее:
<ul>
<li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li>
<li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li>
</ul>
что именно то, что я хочу, кроме для списков части. Поэтому я попытался зациклить его, что дает мне метки, отформатированные по-разному:
{% for item in profile_form.notify_new_friends %}
{{ item }}
{% endfor %}
что дает мне:
<label><input type="radio" name="notify_new_friends" value="0" /> Immediately</label>
<label><input type="radio" name="notify_new_friends" value="1" /> Never</label>
Итак, проблема здесь в том, что он перестает использовать label for
и начинает использовать просто label
чтобы обернуть все это.
Я также пытался сделать что-то подобное, но тогда label
и label_tag
ничего не представляет.
{{ profile_form.notify_new_friends.0 }}
{{ profile_form.notify_new_friends.0.label_tag }}
{{ profile_form.notify_new_friends.0.label }}
так кто-нибудь знает как я могу сделать эту правильно!?
к твоему сведению, это мой forms.py:
self.fields['notify_new_friends'] = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect, choices=NOTIFICATION_CHOICES)
4 ответов
в моем коде я обнаружил, что изменение Виджет от
forms.RadioSelect
to
forms.RadioSelect(attrs={'id': 'value'})
волшебным образом приводит к тому, что tag
значение для включения id
атрибут с индексом добавленного элемента. Если вы используете
{% for radio in form.foo %}
<li>
{{ radio }}
</li>
{% endfor %}
в форме вы получаете label
обмоталась вокруг input
. Если вы хотите более обычного input
следовал по label
, вам нужно сделать это:
{% for radio in form.value %}
<li>
{{ radio.tag }}
<label for="value_{{ forloop.counter0 }}">{{ radio.choice_label }}</label>
</li>
{% endfor %}
к сожалению, это сложнее, чем должно быть, кажется, вам нужно переопределить по крайней мере 2 класса: RadioRenderer
и RadioInput
. Следующее должно помочь вам начать работу, но вам может потребоваться немного настроить его.
сначала создайте пользовательский виджет ввода радиокнопок. Единственная цель переопределения метода рендеринга - избавиться от раздражающей структуры Django enforces (<label><input /></label>
) где вместо этого мы хотим наши (<label /><input />
):
class CustomRadioInput(RadioInput):
def render(self, name=None, value=None, attrs=None, choices=()):
name = name or self.name
value = value or self.value
attrs = attrs or self.attrs
if 'id' in self.attrs:
label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
else:
label_for = ''
choice_label = conditional_escape(force_unicode(self.choice_label))
return mark_safe(u'%s<label%s>%s</label>' % (self.tag(), label_for, choice_label))
теперь нам нужно переопределить RadioRenderer
для:
- заставить его использовать наш пользовательский виджет ввода радио
- удалить
<li>
обертывание каждого поля ввода и<ul>
накрутка всех полей ввода:
что-то в этом роде должно сделать:
class RadioCustomRenderer(RadioFieldRenderer):
def __iter__(self):
for i, choice in enumerate(self.choices):
yield CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, i)
def __getitem__(self, idx):
choice = self.choices[idx]
return CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
def render(self):
return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self]))
наконец проинструктировать Django использовать пользовательский рендерер
notify_new_friends = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect(renderer=RadioCustomRenderer), choices=NOTIFICATION_CHOICES)
пожалуйста, имейте в виду: теперь это выводит переключатели вместе с охватывающей <td>
отсюда вам нужно построить таблицу вокруг него в вашем шаблоне, что-то вроде этих строк:
<table>
<tr>
<td><label for="{{field.auto_id}}">{{field.label}}</label></td>
<td>{{ field.errors }} {{field}}</td>
</tr>
</table>
поскольку это не кажется хорошим способом сделать это, я решил изменить сгенерированный код с помощью jQuery.
// First remove the ul and li tags
$('.radio ul').contents().unwrap();
$('.radio li').contents().unwrap();
// Then move the input to outside of the label
$('.radio > label > input').each(function() {
$(this).parent().before(this);
});
// Then apply the jQuery UI buttonset
$( ".radio" ).buttonset();
Это заставило его перейти от:
<ul>
<li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li>
<li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li>
</ul>
в:
<input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /><label for="id_notify_new_friends_0"> Immediately</label></li>
<input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /><label for="id_notify_new_friends_1"> Never</label></li>
и мой стиль jQuery UI отлично работает.
Try like this , I got it..
from django.forms.widgets import RadioFieldRenderer
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
class RadioCustomRenderer( RadioFieldRenderer ):
def render( self ):
return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self]))
in form
widgets = {
'validity': forms.RadioSelect(renderer=RadioCustomRenderer),
}