setting help_text for each choice in a RadioSelect
I can set the help_text attribute on any form field, but is it possible to set help_text on the choices used for a RadioSelect()?
I'd looking for a clean way to show some help information under each radio button.
Below is the code for the model and the form, I can render the name attribute in a template with the label, input element and help text. I'd also like to be able to render membership_type attribute with a label ('Membership Type'), radio buttons ('open membership' and 'closed membership'), and help text associated to each radio element ('anyone can join this group' and 'only select members can join this group').
class Group(models.Model):
MEMBERSHIP_CHOICES = (
('O', 'Open membership'),
('C', 'Closed membership'),
)
name = models.CharField(max_length=255)
membership_type = models.CharField(max_length=1, choices=MEMBERSHIP_CHOICES, default="O")
class GroupForm(forms.ModelForm):
name = forms.CharField(label="Group name", help_text="Enter a name for your new group")
class Meta:
开发者_StackOverflow中文版 model = Group
widgets = { "membership_type": forms.RadioSelect }
@Rishabh is correct but I'll elaborate further as, at first glance, it doesn't appear to be the solution, although it is; or, at least, it can be kludged to get a useful effect without having to dive too deep into django forms.
The second element of the tuple is presented inside the "label" tag - so any 'inline elements' are permissible; for example:
The desired result
Or something like it
<ul>
<li><label for="id_ticket_0">
<input type="radio" id="id_ticket_0" value="PARTTIME" name="ticket">
<em>Part Time</em> Valid on Friday Night and Saturday Only
</label></li>
<li><label for="id_ticket_1">
<input type="radio" id="id_ticket_1" value="DAYTIME" name="ticket">
<em>Casual</em> Valid on Saturday Only
</label></li>
<li><label for="id_ticket_2">
<input type="radio" id="id_ticket_2" value="EARLYBIRD" name="ticket">
<em>Early Bird</em> Valid on Friday, Saturday, and Sunday. $15 discount for booking before 1am January 3rd, 2011
</label></li>
</ul>
The simple example
The trick is to "mark_safe" the content of the description then stuff whatever you need into:
from django.utils.safestring import mark_safe
choices = (
('1', mark_safe(u'<em>One</em> | This is the first option. It is awesome')),
('2', mark_safe(u'<em>Two</em> | This is the second option. Good too.'))
)
The complex example
So in this example we:
- assemble the choices into a list (any iterable structure will do)
- pass the structure to the form's init to create our radio options on the fly
- use a comprehension list to create an extended description for each radio option
The data structure: Tickets are my own classes and they have attributes:
- tickets.code - as in a ticket code
- label - a pithy short description
- help - a longer description
But more about that later. First lets create some instances:
from mymodule import ticket
# so lets create a few
fulltime = ticket('FULLTIME',160,'Full Time',
"Valid Monday to Friday inclusive")
parttime = ticket('PARTTIME',110,'Full Time',
"Valid outside of business hours only")
daytime = ticket('DAYTIME',70,'Day Time',
"Valid only on weekends and public holidays")
# and put them together in a list any way you like
available_tickets = [fulltime, parttime, daytime]
# now create the form
OrderForm(tickets=available_tickets)
That probably happened in your view code. Now to see what happens in the form
class OrderForm(ModelForm):
def __init__(self, *args, **kwargs):
self.tickets = kwargs.pop('tickets')
super(OrderForm, self).__init__(*args, **kwargs)
choices = [(t.code, mark_safe(u'<em>%s</em> %s' % (t.label, t.help)))
for t in self.tickets]
self.fields['ticket'] = forms.ChoiceField(
choices = choices,
widget = forms.RadioSelect()
)
For others coming across this 10+ years later, I was able to do this by creating a custom widget that overrides the default template for radio buttons, and passing custom attributes to it.
# Custom widget
class RadioSelectHelpTextWidget(forms.RadioSelect):
option_template_name = 'custom_templates/forms/radio_option_help_text.html'
# Form class that calls widgets, passed custom attributes to widget
class TemplateCreateForm(ModelForm):
created_by = forms.ModelChoiceField(required=False,queryset=User.objects.none())
class Meta:
model = Template
fields = ['name', 'type', 'created_by']
widgets = {
'name': forms.TextInput(attrs={'class': 'input'}),
'type': RadioSelectHelpTextWidget(
attrs={
'help_text': {
'custom': 'This is custom help text.',
'html': 'This is help text for html.'
}
}
)
}
Template for custom radio buttons (custom_templates/forms/radio_option_help_text.html)
{% load custom_template_filters %}
{% if widget.wrap_label %}
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>
{% endif %}
{% include "django/forms/widgets/input.html" %}
{% if widget.wrap_label %}
{{ widget.label }}
{% if widget.attrs.help_text %}
{% if widget.value in widget.attrs.help_text %}
<p class="is-size-7">
{{ widget.attrs.help_text|dict_get:widget.value }}
</p>
{% endif %}
{% endif %}
</label>
{% endif %}
The result:
Assuming you're using RadioSelect
as a widget for forms.ChoiceField
, you can do something like:
choices = (('1', 'First help_text here'),
('2', 'Second help_text here'),
('3', 'Third help_text here'),
)
class MyForm(forms.Form):
...
choice = forms.ChoiceField(widget = RadioSelect, choices = choices)
This isn't a strict use of help_text
but it should get the job done in most cases.
精彩评论