Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

289
Views
Django add attributes to SelectMultiple <option> tags

There's a great explanation here on adding attributes to <option> tags within a django form field. But this is only for a Select widget. I want to do the same for a SelectMultiple widget.

I tried the following (subclass Select and SelectMultiple and reference MySelectMultiple when creating the Model form field employees):

class MySelect(forms.Select):

    def __init__(self, *args, **kwargs):
            super(MySelect, self).__init__(*args, **kwargs)

    def render_option(self, selected_choices, option_value, option_label):
        # original forms.Select code #
        return u'<option custom_attribute="foo">...</option>'

class MySelectMultiple(MySelect):
    def __init__(self, *args, **kwargs):
        super(MySelectMultiple, self).__init__(*args, **kwargs) 

employees = forms.ModelMultipleChoiceField(
                    widget=MySelectMultiple(attrs={}),
                    queryset=Employee.objects.all(),
                )

But the rendered form is still showing as a Select widget, not a SelectMultiple widget.

I can provide attrs={'multiple':'multiple'} to MySelectMultiple to make the form field render as a multiple select widget - but when the form is saved, only a single value is saved (not multiple values)!

How can I have the form render as a multiple choice field AND save all of the selected values? Thank you.

about 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Your select multiple should inherit from SelectMultiple rather than Select:

class MySelectMultiple(SelectMultiple):
    def render_option(self, selected_choices, option_value, option_label):
        # original forms.Select code #
        return u'<option custom_attribute="foo">...</option>'

It looks like your __init__ method isn't necessary, since it just calls super().

about 4 years ago · Santiago Trujillo Report

0

SelectMultiple inherits from Select, you just need to override the create_option method to get the same results:

class MySelectMultiple(forms.SelectMultiple):
    def create_option(self, name, value, *args, **kwargs):
        option = super().create_option(name, value, *args, **kwargs)
        if value:
            instance = self.choices.queryset.get(pk=value)  # get instance
            option['attrs']['custom_attr'] = instance.field_name  # set option attribute
        return option

about 4 years ago · Santiago Trujillo Report

0

Alright, figured out: by using:

class MySelectMultiple(MySelect):
    def __init__(self, *args, **kwargs):
        super(MySelectMultiple, self).__init__(*args, **kwargs) 

I was still using the django native Select but just calling it MySelectMultiple. I needed to import the rest of SelectMultiple.

So, instead of:

class MySelectMultiple(MySelect):
    def __init__(self, *args, **kwargs):
        super(MySelectMultiple, self).__init__(*args, **kwargs) 

The class needs to be complete (copy/paste of native django code for SelectMultiple):

class MySelectMultiple(MySelect):
    allow_multiple_selected = True

    def __init__(self, *args, **kwargs):
        super(MySelectMultiple, self).__init__(*args, **kwargs)


    def render(self, name, value, attrs=None, choices=()):
        if value is None:
            value = []
        final_attrs = self.build_attrs(attrs, name=name)
        output = [format_html('<select multiple="multiple"{0}>', forms.utils.flatatt(final_attrs))]
        options = self.render_options(choices, value)
        if options:
            output.append(options)
        output.append('</select>')
        return mark_safe('\n'.join(output))

    def value_from_datadict(self, data, files, name):
        if isinstance(data, (MultiValueDict, MergeDict)):
            return data.getlist(name)
        return data.get(name, None)
about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!