You can define your field in the ModelForm
as a ModelMultipleChoiceField
(docs) which will hide most of the implementation details and output the exact same result.
Here is an example of an actual implementation I've made in the past
class InterestForm(forms.ModelForm):
name = forms.ModelMultipleChoiceField(
queryset=Interest.objects.all(),
required=False,
widget=FilteredSelectMultiple("verbose name", is_stacked=False),
)
class Meta:
model = Interest
fields = ["name"]
Alternatively, if you want more control over how it's rendered, you can write the html yourself. Make sure to include the multiple
property in the select
tag:
<label for="{{ form.my_m2m_field.auto_id }}">{{ form.my_m2m_field.name }}</label>
<select name="{{ form.my_m2m_field.html_name }}" id="{{ form.my_m2m_field.auto_id }}" multiple>
{% for item in form.my_m2m_field.field.queryset %}
<option value="{{ item.pk }}">{{ item.name }}</option>
{% endfor %}
</select>