Django

Code

Ticket #4412: 4412-r6025.diff

File 4412-r6025.diff, 10.7 kB (added by russellm, 1 year ago)

Update to r6025, plus some polish to docs and implementation

  • django/db/models/base.py

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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.