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?
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:
# ...
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'}}
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With