Reputation: 311
I have a form (edited for brevity) as follows:
class InteractionForm(forms.Form):
def __init__(self, *args, **kwargs):
# Each object within this queryset is a model object of type InteractionChoice
choices_qs = interaction.interactionchoice_set.all()
self.fields['choices'] = forms.ModelChoiceField(
widget=forms.RadioSelect(),
queryset=choices_qs,
The InteractionChoice
model looks like:
class InteractionChoice(models.Model):
interaction = models.ForeignKey(Interaction)
name = models.CharField(max_length=255)
is_answer = models.BooleanField(default=False)
An instance of InteractionForm
is passed from a view to a template and rendered via:
{{ form.choices }}
My question is whether there is a way to iterate over each choice in my template and access one of its properties -- specifically, the is_answer
property defined in InteractionChoice
. The purpose being to customize how a choice is displayed if it is indeed the answer. More specifically, if is_answer
is True, I'd possibly change the class
attribute on the <label>
for that choice.
Perhaps, I'm approaching this problem from the wrong direction. If anyone has pointers for alternative ideas, I'd be happy to hear them.
Thanks in advance.
Update 1:
Thinking about this more after @rczajka's response, I don't believe I can achieve what I'm hoping to do in the template code. Instead, if the purpose is to modify the tag's class attribute, I should perhaps be looking to subclass and override certain methods in forms.widgets.RadioInput
, forms.widgets.RadioFieldRenderer
, and forms.widgets.RadioSelect
. I'll dig into this more.
Upvotes: 3
Views: 4096
Reputation: 81
As of Django 3.2, you can iterate over the choices in templates. The RadioSelect widget docs state that you can loop over RadioSelect
generated markup
For more granular control over the generated markup, you can loop over the radio buttons in the template.
Here's an example of how you can do it:
<ul>
{% for choice in form.choices %}
<li>{{ choice }}</li>
{% endfor %}
</ul>
Upvotes: 0
Reputation: 5343
I found a similar problem but solved it in a different way.
How to get ModelChoiceField instances in the template
Iterating over the field's queryset property.
Upvotes: 1
Reputation: 311
I came up with one solution that addresses this problem. It's hackish, to say the least, but it's the only approach I've thought of that works thus far without a lot of back-end changes to my existing design.
My approach stemmed from this article on subclassing `RadioFieldRenderer' and 'RadioSelect'.
In the __unicode__
method for an InteractionChoice
model, I return:
return self.name + "_" + str(self.is_answer)
which is the value used for a radio button's label (amongst other things). I then subclassed forms.widgets.RadioInput
, forms.widgets.RadioFieldRenderer
, and forms.widgets.RadioSelect
.
For the custom RadioInput class, I overrode its __unicode__
method to include logic to append a class
string – whose value is ultimately dictated by the string returned from the unicode method in InteractionChoice
– to the <label>
tag string it returns.
For the custom RadioFieldRenderer class, I overrode __iter__
and __getitem__
to use the custom RadioInput class.
For the custom RadioSelect class, I overrode the renderer
property to use my custom radio field renderer.
This is obviously far from an ideal solution. Hopefully, a better one will arise.
Upvotes: 1
Reputation: 1840
You should subclass ModelChoiceField and override label_from_instance. It says so here: https://docs.djangoproject.com/en/dev/ref/forms/fields/#modelchoicefield:
The unicode method of the model will be called to generate string representations of the objects for use in the field's choices; to provide customized representations, subclass ModelChoiceField and override label_from_instance. This method will receive a model object, and should return a string suitable for representing it.
Upvotes: 0