Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django form field choices, adding an attribute

Tags:

PLANNING_CHOICES = (     ('0',u'Every morning'),     ('1',u'Every night'),     ('2',u'Never'), )  planning = forms.ChoiceField(required=True, choices = PLANNING_CHOICES) 

Having a such form field named planning, I need to add title attribute to choices and in the end renders as this:

<select>     <option value="0" title="bla1">Every morning</option>     <option value="1" title="bla2">Every night</option>     <option value="2" title="bla3">Never</option> </select> 

How can it be achieved ?

like image 454
Hellnar Avatar asked Feb 23 '11 10:02

Hellnar


People also ask

How do I add a class or id attribute to a django form field?

In order to add a class or id attribute to a form in Django, we have to place a widget=form. TextInput (or widget= form. EmailInput, if email input) within the form field (because it's a text field). Inside of this widget, we then have to put, attrs={'class':'some_class'}.

How do you define choice fields in django?

Choices can be any sequence object – not necessarily a list or tuple. The first element in each tuple is the actual value to be set on the model, and the second element is the human-readable name. Let us create a choices field with above semester in our django project named geeksforgeeks.

How do I make a field optional in django?

Enter Venue Name, Address and Zip/Post Code in the blank form, but leave the Contact Phone, Web Address and Email Address fields blank. Click “Save”. Your screen should look something like Figure 7.5.


2 Answers

You'd have to subclass the field to take whatever means of specifying the title you'd like and the widget to display the new attribute.

If you had something like this (note: entirely untested):

from django import forms from django.utils.html import escape from django.utils.encoding import force_unicode  class SelectWithTitles(forms.Select):     def __init__(self, *args, **kwargs):         super(SelectWithTitles, self).__init__(*args, **kwargs)         # Ensure the titles dict exists         self.titles = {}      def render_option(self, selected_choices, option_value, option_label):         title_html = (option_label in self.titles) and \             u' title="%s" ' % escape(force_unicode(self.titles[option_label])) or ''         option_value = force_unicode(option_value)         selected_html = (option_value in selected_choices) and u' selected="selected"' or ''         return u'<option value="%s"%s%s>%s</option>' % (             escape(option_value), title_html, selected_html,             conditional_escape(force_unicode(option_label)))  class ChoiceFieldWithTitles(forms.ChoiceField):     widget = SelectWithTitles      def __init__(self, choices=(), *args, **kwargs):         choice_pairs = [(c[0], c[1]) for c in choices]         super(ChoiceFieldWithTitles, self).__init__(choices=choice_pairs, *args, **kwargs)         self.widget.titles = dict([(c[1], c[2]) for c in choices]) 

...you should be able to do this:

PLANNING_CHOICES_WITH_TITLES = (     ('0', 'Every morning', 'bla1'),     ('1', 'Every night',   'bla2'),     ('2', 'Never',         'bla3'), )  planning = forms.ChoiceFieldWithTitles(     required=True, choices=PLANNING_CHOICES_WITH_TITLES) 
like image 167
Jonny Buchanan Avatar answered Sep 24 '22 23:09

Jonny Buchanan


Here is a general solution to allow attributes in options in a Select widget, SelectMultiple widget and also in Select2 widgets.

It has been tested on Django 2.1 and should work for other versions as well (tell me in comments).

from django.forms.widgets import Select, SelectMultiple  class SelectWOA(Select):     """     Select With Option Attributes:         subclass of Django's Select widget that allows attributes in options,          like disabled="disabled", title="help text", class="some classes",               style="background: color;"...      Pass a dict instead of a string for its label:         choices = [ ('value_1', 'label_1'),                     ...                     ('value_k', {'label': 'label_k', 'foo': 'bar', ...}),                     ... ]     The option k will be rendered as:         <option value="value_k" foo="bar" ...>label_k</option>     """      def create_option(self, name, value, label, selected, index,                        subindex=None, attrs=None):         if isinstance(label, dict):             opt_attrs = label.copy()             label = opt_attrs.pop('label')         else:              opt_attrs = {}         option_dict = super(SelectWOA, self).create_option(name, value,              label, selected, index, subindex=subindex, attrs=attrs)         for key,val in opt_attrs.items():             option_dict['attrs'][key] = val         return option_dict 

Here is an example that you can try in your forms.py:

choices = [('b', 'blue'),            ('g', {'label': 'green', 'disabled': 'disabled'}),            ('c', {'label': 'cyan',                    'title': 'Kind of violet',                   'style': 'background: cyan;',                  }),            ('r', 'red'), ]  colors = forms.ChoiceField(     label="Colors",     choices=choices,     widget=SelectWOA) 

The colors field can be rendered in Django shell to check the result:

(myvenv) $ ./manage.py shell >>> from myapp.forms import * >>> choices = ... >>> colors = ... >>> colors.widget.render('mycolors','') '''<select name="mycolors">       <option value="b">blue</option>       <option value="g" disabled="disabled">green</option>       <option value="c" title="Kind of violet" style="background: cyan;">cyan</option>       <option value="r">red</option>  </select>''' 

To allow multiple selections, add this:

class SelectMultipleWOA(SelectWOA, SelectMultiple):     """      SelectMultipleWOA widget works like SelectMultiple, with options attrs.     See SelectWOA.     """     pass  colors = forms.MultipleChoiceField(     label="Colors",     choices=choices,     widget=SelectMultipleWOA) 

It will render <select name="mycolors" multiple>...<\select>.

You can use SelectWOA and SelectMultipleWOA to extend the Select2 widgets:

from django_select2.forms import Select2Mixin  class Select2MultipleWidgetWOA(Select2Mixin, SelectMultipleWOA):     """     Select2 drop in widget for multiple select.     Works just like Select2MultipleWidget but with options attrs.     """     pass  colors = forms.MultipleChoiceField(     label="Colors",     choices=choices,     widget=Select2MultipleWidgetWOA(         attrs={'data-placeholder': 'Any color',                'data-close-on-select': 'false',                'style': 'width:280px; height:36px;',                'title': 'Type a word to filter the menu',}     ) ) 

It will render something like:

'''<select name="mycolors" data-placeholder="Any color"      class="django-select2" data-minimum-input-length="0" multiple      style="width:280px; height:36px;" data-close-on-select="false"      data-allow-clear="false" title="Type a word to filter the menu">        <option value="b">blue</option>        <option value="g" disabled="disabled">green</option>        <option value="c" title="Kind of violet" style="background: cyan;">cyan</option>        <option value="r">red</option>     </select>''' 
like image 36
Edouard Thiel Avatar answered Sep 22 '22 23:09

Edouard Thiel