Ticket #4412: 4412-r6025.diff

File 4412-r6025.diff, 10.7 KB (added by Russell Keith-Magee, 11 years ago)

Update to r6025, plus some polish to docs and implementation

  • django/db/models/base.py

     
    324324
    325325    def _get_FIELD_display(self, field):
    326326        value = getattr(self, field.attname)
    327         return force_unicode(dict(field.choices).get(value, value), strings_only=True)
     327        flatchoices = []
     328        for choice in field.choices:
     329            if type(choice[1]) in (list, tuple):
     330                flatchoices.extend(choice[1])
     331            else:
     332                flatchoices.append(choice)
     333        return force_unicode(dict(flatchoices).get(value, value), strings_only=True)
    328334
    329335    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
    330336        qn = connection.ops.quote_name
  • django/newforms/fields.py

     
    473473        value = smart_unicode(value)
    474474        if value == u'':
    475475            return value
    476         valid_values = set([smart_unicode(k) for k, v in self.choices])
     476        valid_values = []
     477        for k, v in self.choices:
     478            if type(v) in (tuple, list):
     479                valid_values.extend([k2[0] for k2 in v])
     480            else:
     481                valid_values.append(k)
     482        valid_values = set([smart_unicode(v) for v in valid_values])       
    477483        if value not in valid_values:
    478484            raise ValidationError(ugettext(u'Select a valid choice. That choice is not one of the available choices.'))
    479485        return value
     
    494500            raise ValidationError(ugettext(u'Enter a list of values.'))
    495501        new_value = [smart_unicode(val) for val in value]
    496502        # Validate that each value in the value list is in self.choices.
    497         valid_values = set([smart_unicode(k) for k, v in self.choices])
     503        valid_values = []
     504        for k, v in self.choices:
     505            if type(v) in (tuple, list):
     506                valid_values.extend([k2[0] for k2 in v])
     507            else:
     508                valid_values.append(k)
     509        valid_values = set([smart_unicode(v) for v in valid_values])       
    498510        for val in new_value:
    499511            if val not in valid_values:
    500512                raise ValidationError(ugettext(u'Select a valid choice. %s is not one of the available choices.') % val)
  • django/newforms/widgets.py

     
    174174        output = [u'<select%s>' % flatatt(final_attrs)]
    175175        str_value = force_unicode(value) # Normalize to string.
    176176        for option_value, option_label in chain(self.choices, choices):
    177             option_value = force_unicode(option_value)
    178             selected_html = (option_value == str_value) and u' selected="selected"' or ''
    179             output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
     177            if type(option_label) in (list, tuple):
     178                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
     179                for group_option_value, group_option_label in option_label:
     180                    group_option_value = force_unicode(group_option_value)
     181                    selected_html = (group_option_value == str_value) and u' selected="selected"' or ''
     182                    output.append(u'<option value="%s"%s>%s</option>' % (escape(group_option_value), selected_html, escape(force_unicode(group_option_label))))
     183                output.append(u'</optgroup>')
     184            else:
     185                option_value = force_unicode(option_value)
     186                selected_html = (option_value == str_value) and u' selected="selected"' or ''
     187                output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
    180188        output.append(u'</select>')
    181189        return u'\n'.join(output)
    182190
     
    211219        output = [u'<select multiple="multiple"%s>' % flatatt(final_attrs)]
    212220        str_values = set([force_unicode(v) for v in value]) # Normalize to strings.
    213221        for option_value, option_label in chain(self.choices, choices):
    214             option_value = force_unicode(option_value)
    215             selected_html = (option_value in str_values) and ' selected="selected"' or ''
    216             output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
     222            if type(option_label) in (list, tuple):
     223                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
     224                for group_option_value, group_option_label in option_label:
     225                    group_option_value = force_unicode(group_option_value)
     226                    selected_html = (group_option_value in str_values) and u' selected="selected"' or ''
     227                    output.append(u'<option value="%s"%s>%s</option>' % (escape(group_option_value), selected_html, escape(force_unicode(group_option_label))))
     228                output.append(u'</optgroup>')
     229            else:
     230                option_value = force_unicode(option_value)
     231                selected_html = (option_value in str_values) and u' selected="selected"' or ''
     232                output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
    217233        output.append(u'</select>')
    218234        return u'\n'.join(output)
    219235
  • tests/regressiontests/forms/tests.py

     
    395395<option value="4">4</option>
    396396</select>
    397397
     398Choices can be nested one level in order to create HTML optgroups:
     399>>> w = Select(choices=(('outer1', 'Outer 1'), ('Group 1', (('inner1', 'Inner 1'), ('inner2', 'Inner 2')))))
     400>>> print w.render('nestchoice', None)
     401<select name="nestchoice">
     402<option value="outer1">Outer 1</option>
     403<optgroup label="Group 1">
     404<option value="inner1">Inner 1</option>
     405<option value="inner2">Inner 2</option>
     406</optgroup>
     407</select>
     408>>> print w.render('nestchoice', 'outer1')
     409<select name="nestchoice">
     410<option value="outer1" selected="selected">Outer 1</option>
     411<optgroup label="Group 1">
     412<option value="inner1">Inner 1</option>
     413<option value="inner2">Inner 2</option>
     414</optgroup>
     415</select>
     416>>> print w.render('nestchoice', 'inner1')
     417<select name="nestchoice">
     418<option value="outer1">Outer 1</option>
     419<optgroup label="Group 1">
     420<option value="inner1" selected="selected">Inner 1</option>
     421<option value="inner2">Inner 2</option>
     422</optgroup>
     423</select>
     424
    398425# NullBooleanSelect Widget ####################################################
    399426
    400427>>> w = NullBooleanSelect()
     
    536563>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
    537564u'<select multiple="multiple" name="nums">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
    538565
     566Choices can be nested one level in order to create HTML optgroups:
     567>>> w = SelectMultiple(choices=(('outer1', 'Outer 1'), ('Group 1', (('inner1', 'Inner 1'), ('inner2', 'Inner 2')))))
     568>>> print w.render('nestchoice', None)
     569<select multiple="multiple" name="nestchoice">
     570<option value="outer1">Outer 1</option>
     571<optgroup label="Group 1">
     572<option value="inner1">Inner 1</option>
     573<option value="inner2">Inner 2</option>
     574</optgroup>
     575</select>
     576>>> print w.render('nestchoice', ['outer1'])
     577<select multiple="multiple" name="nestchoice">
     578<option value="outer1" selected="selected">Outer 1</option>
     579<optgroup label="Group 1">
     580<option value="inner1">Inner 1</option>
     581<option value="inner2">Inner 2</option>
     582</optgroup>
     583</select>
     584>>> print w.render('nestchoice', ['inner1'])
     585<select multiple="multiple" name="nestchoice">
     586<option value="outer1">Outer 1</option>
     587<optgroup label="Group 1">
     588<option value="inner1" selected="selected">Inner 1</option>
     589<option value="inner2">Inner 2</option>
     590</optgroup>
     591</select>
     592>>> print w.render('nestchoice', ['outer1', 'inner2'])
     593<select multiple="multiple" name="nestchoice">
     594<option value="outer1" selected="selected">Outer 1</option>
     595<optgroup label="Group 1">
     596<option value="inner1">Inner 1</option>
     597<option value="inner2" selected="selected">Inner 2</option>
     598</optgroup>
     599</select>
     600
    539601# RadioSelect Widget ##########################################################
    540602
    541603>>> w = RadioSelect()
  • docs/newforms.txt

     
    10831083    * Validates that the given value exists in the list of choices.
    10841084
    10851085Takes one extra argument, ``choices``, which is an iterable (e.g., a list or
    1086 tuple) of 2-tuples to use as choices for this field.
     1086tuple) of 2-tuples to use as choices for this field. This argument accepts
     1087the same formats as the ``choices`` argument to a model field. See the
     1088`model API documentation on choices`_ for more details.
    10871089
     1090.. _model API documentation on choices: ../model-api#choices
     1091
    10881092``DateField``
    10891093~~~~~~~~~~~~~
    10901094
  • docs/model-api.txt

     
    552552    class Foo(models.Model):
    553553        gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
    554554
     555You can also collect your available choices into named groups, which will
     556be used for display purposes::
     557
     558    MEDIA_CHOICES = (
     559        ('Audio', (
     560                ('vinyl', 'Vinyl'),
     561                ('cd', 'CD'),
     562            )
     563        ),
     564        ('Video', (
     565                ('vhs', 'VHS Tape'),
     566                ('dvd', 'DVD'),
     567            )
     568        ),
     569        ('unknown', 'Unknown'),
     570    )
     571
     572The first element in each tuple is the name to apply to the group. The
     573second element is an iterable of 2-tuples, with each 2-tuple containing
     574a value and a human-readable name for an option. Grouped options may be
     575combined with ungrouped options within a single list (such as the
     576`unknown` option in this example).
     577
    555578For each model field that has ``choices`` set, Django will add a method to
    556579retrieve the human-readable name for the field's current value. See
    557580`get_FOO_display`_ in the database API documentation.
Back to Top