Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add attributes to option tags in django ?

I have to add title attribute to options of the ModelChoiceField. Here is my admin code for that:

class LocModelForm(forms.ModelForm):
        def __init__(self,*args,**kwargs):
            super(LocModelForm,self).__init__(*args,**kwargs)
            self.fields['icons'] = forms.ModelChoiceField(queryset = Photo.objects.filter(galleries__title_slug = "markers"))
            self.fields['icons'].widget.attrs['class'] = 'mydds'
                

        class Meta:
            model = Loc
            widgets = {
                'icons' : forms.Select(attrs={'id':'mydds'}), 
                }
        
        class Media:
            css = {
                "all":("/media/css/dd.css",)
                }
            js=(
                '/media/js/dd.js',
                )

class LocAdmin(admin.ModelAdmin):
    form = LocModelForm

I can add any attribute to select widget, but I don't know how to add attributes to option tags. Any idea?

like image 633
iva123 Avatar asked Jun 25 '11 12:06

iva123


2 Answers

First of all, don't modify fields in __init__, if you want to override widgets use Meta inner class, if you want to override form fields, declare them like in a normal (non-model) form.

If the Select widget does not do what you want, then simply make your own. Original widget uses render_option method to get HTML representation for a single option — make a subclass, override it, and add whatever you want.

class MySelect(forms.Select):
    def render_option(self, selected_choices, option_value, option_label):
        # look at the original for something to start with
        return u'<option whatever>...</option>'

class LocModelForm(forms.ModelForm):
    icons = forms.ModelChoiceField(
        queryset = Photo.objects.filter(galleries__title_slug = "markers"),
        widget = MySelect(attrs = {'id': 'mydds'})
    )

    class Meta:
        # ...
        # note that if you override the entire field, you don't have to override
        # the widget here
    class Media:
        # ...
like image 124
Cat Plus Plus Avatar answered Oct 23 '22 07:10

Cat Plus Plus


I had a similar problem, where I needed to add a custom attribute to each option dynamically. But in Django 2.0, the html rendering was moved into the Widget base class, so modifying render_option no longer works. Here is the solution that worked for me:

from django import forms

class CustomSelect(forms.Select):
    def __init__(self, *args, **kwargs):
        self.src = kwargs.pop('src', {})
        super().__init__(*args, **kwargs)

    def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
        options = super(CustomSelect, self).create_option(name, value, label, selected, index, subindex=None, attrs=None)
        for k, v in self.src.items():
            options['attrs'][k] = v[options['value']]
        return options

class CustomForm(forms.Form):
    def __init__(self, *args, **kwargs):
        src = kwargs.pop('src', {})
        choices = kwargs.pop('choices', ())
        super().__init__(*args, **kwargs)
        if choices:
            self.fields['custom_field'].widget = CustomSelect(attrs={'class': 'some-class'}, src=src, choices=choices)

    custom_field = forms.CharField(max_length=100)

Then in views, render a context with {'form': CustomForm(choices=choices, src=src)} where src is a dictionary like this: {'attr-name': {'option_value': 'attr_value'}}.

like image 7
kayoz Avatar answered Oct 23 '22 08:10

kayoz