Reputation: 18919
I have a form:
class AccessoriesForm(forms.Form):
available_accessories = Parts.objects.all()
accessory = forms.ModelMultipleChoiceField(
queryset=available_accessories,
widget=forms.CheckboxSelectMultiple(
attrs={'class': 'accessory-checkbox'}
),
label=None
)
And in my template:
{% for field in accessory_form %}
{{ field }}
{% endfor %}
This gives me a list of checkboxes. But I want to also be able to target individual checkboxes so that I can add a unique image beside each one. If I could get the name of each field, that would work.
I have tried:
{% for field in accessory_form %}
{{ field }}{{ field.name }}
{% endfor %}
and:
{% for field in accessory_form %}
{{ field }}{{ field.label }}
{% endfor %}
But that just gives me the label for the field.
Upvotes: 1
Views: 198
Reputation: 18919
For Completeness, here is my solution:
I store the necessary fields for the available accessories in a python dict, then pass to javascript in the template:
var AccessoryArray = new Array();
{% for accessory in available_accessories %}
var this_object = new Object();
this_object.description = "{{ accessory.full_description }}";
this_object.filename = "{{ accessory.filename }}";
AccessoryArray[{{ accessory.pk }}] = this_object;
{% endfor %}
$(document).ready(function() {
// iterate through the accessory checkboxes
$('input.accessory-checkbox').each(function(){
// construct output for image and full description
var filename_output = '<img src="' + media_url + 'parts/' + AccessoryArray[$(this).val()].filename + '" />';
var description_output = '<span class="accessory-description-text">' + AccessoryArray[$(this).val()].description + '</span>';
// insert html after the input label
$(this).parent().after(description_output).after(filename_output);
});
});
Upvotes: 0
Reputation: 37319
I recommend writing your own subclass of the CheckboxSelectMultiple
widget to do this, overriding its render
method. The rendering code is pretty straightforward, but that widget returns the entire <ul>
element with the checkboxes pre-rendered - trying to pull out the representations of the individual checkboxes in a template is going to be tricky at best.
Something like this:
class ImageCheckboxSelectMultiple(CheckboxSelectMultiple):
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
has_id = attrs and 'id' in attrs
final_attrs = self.build_attrs(attrs, name=name)
output = [u'<ul>']
# Normalize to strings
str_values = set([force_unicode(v) for v in value])
for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
# If an ID attribute was given, add a numeric index as a suffix,
# so that the checkboxes don't all have the same ID attribute.
if has_id:
final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
label_for = u' for="%s"' % final_attrs['id']
else:
label_for = ''
cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
option_value = force_unicode(option_value)
rendered_cb = cb.render(name, option_value)
option_label = conditional_escape(force_unicode(option_label))
# Here's the new part
image_element = u'<img src="/images/some_image.png">'
output.append(u'<li>%s<label%s>%s %s</label></li>' % (image_element, label_for, rendered_cb, option_label))
output.append(u'</ul>')
return mark_safe(u'\n'.join(output))
Depending on your setup you might want to use STATIC_URL
as part of the image path.
Upvotes: 2