import copy import datetime from django.forms import Select from django.test import override_settings from django.utils.safestring import mark_safe from .base import WidgetTest class SelectTest(WidgetTest): widget = Select nested_widget = Select(choices=( ('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))), )) def test_render(self): self.check_html(self.widget(choices=self.beatles), 'beatle', 'J', html=( """""" )) def test_render_none(self): """ If the value is None, none of the options are selected. """ self.check_html(self.widget(choices=self.beatles), 'beatle', None, html=( """""" )) def test_render_label_value(self): """ If the value corresponds to a label (but not to an option value), none of the options are selected. """ self.check_html(self.widget(choices=self.beatles), 'beatle', 'John', html=( """""" )) def test_render_selected(self): """ Only one option can be selected (#8103). """ choices = [('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra')] self.check_html(self.widget(choices=choices), 'choices', '0', html=( """""" )) def test_constructor_attrs(self): """ Select options shouldn't inherit the parent widget attrs. """ widget = Select( attrs={'class': 'super', 'id': 'super'}, choices=[(1, 1), (2, 2), (3, 3)], ) self.check_html(widget, 'num', 2, html=( """""" )) def test_compare_to_str(self): """ The value is compared to its str(). """ self.check_html( self.widget(choices=[('1', '1'), ('2', '2'), ('3', '3')]), 'num', 2, html=( """""" ), ) self.check_html( self.widget(choices=[(1, 1), (2, 2), (3, 3)]), 'num', '2', html=( """""" ), ) self.check_html( self.widget(choices=[(1, 1), (2, 2), (3, 3)]), 'num', 2, html=( """""" ), ) def test_choices_constructor(self): widget = Select(choices=[(1, 1), (2, 2), (3, 3)]) self.check_html(widget, 'num', 2, html=( """""" )) def test_choices_constructor_generator(self): """ If choices is passed to the constructor and is a generator, it can be iterated over multiple times without getting consumed. """ def get_choices(): for i in range(5): yield (i, i) widget = Select(choices=get_choices()) self.check_html(widget, 'num', 2, html=( """""" )) self.check_html(widget, 'num', 3, html=( """""" )) def test_choices_escaping(self): choices = (('bad', 'you & me'), ('good', mark_safe('you > me'))) self.check_html(self.widget(choices=choices), 'escape', None, html=( """""" )) def test_choices_unicode(self): self.check_html( self.widget(choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), 'email', 'ŠĐĆŽćžšđ', html=( """""" ), ) def test_choices_optgroup(self): """ Choices can be nested one level in order to create HTML optgroups. """ self.check_html(self.nested_widget, 'nestchoice', None, html=( """""" )) def test_choices_select_outer(self): self.check_html(self.nested_widget, 'nestchoice', 'outer1', html=( """""" )) def test_choices_select_inner(self): self.check_html(self.nested_widget, 'nestchoice', 'inner1', html=( """""" )) @override_settings(USE_THOUSAND_SEPARATOR=True) def test_doesnt_localize_option_value(self): choices = [ (1, 'One'), (1000, 'One thousand'), (1000000, 'One million'), ] html = """ """ self.check_html(self.widget(choices=choices), 'number', None, html=html) choices = [ (datetime.time(0, 0), 'midnight'), (datetime.time(12, 0), 'noon'), ] html = """ """ self.check_html(self.widget(choices=choices), 'time', None, html=html) def test_options(self): options = list(self.widget(choices=self.beatles).options( 'name', ['J'], attrs={'class': 'super'}, )) self.assertEqual(len(options), 4) self.assertEqual(options[0]['name'], 'name') self.assertEqual(options[0]['value'], 'J') self.assertEqual(options[0]['label'], 'John') self.assertEqual(options[0]['index'], '0') self.assertIs(options[0]['selected'], True) # Template-related attributes self.assertEqual(options[1]['name'], 'name') self.assertEqual(options[1]['value'], 'P') self.assertEqual(options[1]['label'], 'Paul') self.assertEqual(options[1]['index'], '1') self.assertIs(options[1]['selected'], False) def test_optgroups(self): choices = [ ('Audio', [ ('vinyl', 'Vinyl'), ('cd', 'CD'), ]), ('Video', [ ('vhs', 'VHS Tape'), ('dvd', 'DVD'), ]), ('unknown', 'Unknown'), ] groups = list(self.widget(choices=choices).optgroups( 'name', ['vhs'], attrs={'class': 'super'}, )) audio, video, unknown = groups label, options, index = audio self.assertEqual(label, 'Audio') self.assertEqual( options, [{ 'value': 'vinyl', 'type': 'select', 'attrs': {}, 'index': '0_0', 'label': 'Vinyl', 'template_name': 'django/forms/widgets/select_option.html', 'name': 'name', 'selected': False, 'wrap_label': True, }, { 'value': 'cd', 'type': 'select', 'attrs': {}, 'index': '0_1', 'label': 'CD', 'template_name': 'django/forms/widgets/select_option.html', 'name': 'name', 'selected': False, 'wrap_label': True, }] ) self.assertEqual(index, 0) label, options, index = video self.assertEqual(label, 'Video') self.assertEqual( options, [{ 'value': 'vhs', 'template_name': 'django/forms/widgets/select_option.html', 'label': 'VHS Tape', 'attrs': {'selected': True}, 'index': '1_0', 'name': 'name', 'selected': True, 'type': 'select', 'wrap_label': True, }, { 'value': 'dvd', 'template_name': 'django/forms/widgets/select_option.html', 'label': 'DVD', 'attrs': {}, 'index': '1_1', 'name': 'name', 'selected': False, 'type': 'select', 'wrap_label': True, }] ) self.assertEqual(index, 1) label, options, index = unknown self.assertIsNone(label) self.assertEqual( options, [{ 'value': 'unknown', 'selected': False, 'template_name': 'django/forms/widgets/select_option.html', 'label': 'Unknown', 'attrs': {}, 'index': '2', 'name': 'name', 'type': 'select', 'wrap_label': True, }] ) self.assertEqual(index, 2) def test_optgroups_integer_choices(self): """The option 'value' is the same type as what's in `choices`.""" groups = list(self.widget(choices=[[0, 'choice text']]).optgroups('name', ['vhs'])) label, options, index = groups[0] self.assertEqual(options[0]['value'], 0) def test_deepcopy(self): """ __deepcopy__() should copy all attributes properly (#25085). """ widget = Select() obj = copy.deepcopy(widget) self.assertIsNot(widget, obj) self.assertEqual(widget.choices, obj.choices) self.assertIsNot(widget.choices, obj.choices) self.assertEqual(widget.attrs, obj.attrs) self.assertIsNot(widget.attrs, obj.attrs) def test_doesnt_render_required_when_impossible_to_select_empty_field(self): widget = self.widget(choices=[('J', 'John'), ('P', 'Paul')]) self.assertIs(widget.use_required_attribute(initial=None), False) def test_renders_required_when_possible_to_select_empty_field_str(self): widget = self.widget(choices=[('', 'select please'), ('P', 'Paul')]) self.assertIs(widget.use_required_attribute(initial=None), True) def test_renders_required_when_possible_to_select_empty_field_list(self): widget = self.widget(choices=[['', 'select please'], ['P', 'Paul']]) self.assertIs(widget.use_required_attribute(initial=None), True) def test_renders_required_when_possible_to_select_empty_field_none(self): widget = self.widget(choices=[(None, 'select please'), ('P', 'Paul')]) self.assertIs(widget.use_required_attribute(initial=None), True) def test_doesnt_render_required_when_no_choices_are_available(self): widget = self.widget(choices=[]) self.assertIs(widget.use_required_attribute(initial=None), False)