Ticket #27487: ticket_27487.diff
File ticket_27487.diff, 39.7 KB (added by , 8 years ago) |
---|
-
django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
diff --git a/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js b/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js index 3fb1e52..9f68bc1 100644
a b 86 86 } else { 87 87 elem.value = newId; 88 88 } 89 } else if (elemName === 'UL') { 90 var numberOfItems = elem.children.length, 91 // If the input field is wrapped into a label. 92 wrapLabel = (String(elem.getAttribute('data-wrap-label')).toLowerCase() == "true"), 93 // Multiple selection or not. 94 multiple = (String(elem.getAttribute('data-multiple')).toLowerCase() == "true"); 95 96 if (numberOfItems > 0) { 97 if (!multiple) { 98 // Remove previous input checked, the new item will marked as checked. 99 elem.querySelector('input:checked').checked = false; 100 } 101 // Clone an item and include this as the final item of the UL list. 102 // The clone will be the new item and their information will be 103 // replaced with the received data. 104 elem.appendChild(elem.lastElementChild.cloneNode(true)); 105 // newItem's var is the new copy, is necessary to get a new instance to work 106 // with it in order to avoid to modify the cloned item. 107 var newItem = elem.lastElementChild, 108 newItemInput = newItem.getElementsByTagName('input')[0]; 109 110 newItemInput.value = newId; 111 newItemInput.setAttribute('id', elem.id + '_' + numberOfItems); 112 // Mark the new item's input as checked. 113 newItemInput.checked = true; 114 115 if (wrapLabel) { 116 var newItemLabel = newItem.getElementsByTagName('label')[0]; 117 newItemLabel.lastChild.textContent = ' ' + newRepr; 118 newItemLabel.setAttribute('for', elem.id + '_' + numberOfItems); 119 } 120 } else { 121 // The UL list is empty, then is necessary to build the new item. 122 var newItem = document.createElement('li'), 123 newItemInput = document.createElement('input'); 124 125 newItemInput.setAttribute('type', (multiple) ? 'checkbox' : 'radio'); 126 // The elem.id is composed by 'id_' and the name of the related field. 127 // Example: 'id_books', is only necessary to remove 'id_' to get the 128 // name of the field. 129 newItemInput.setAttribute('name', elem.id.replace('id_', '')); 130 newItemInput.setAttribute('id', elem.id + '_0'); 131 // Mark the new item's input as checked. 132 newItemInput.checked = true; 133 newItemInput.value = newId; 134 135 if (wrapLabel) { 136 var newItemLabel = document.createElement('label'); 137 newItemLabel.textContent = ' ' + newRepr; 138 newItemLabel.setAttribute('for', elem.id + '_0'); 139 // Insert input into label. 140 newItemLabel.insertBefore(newItemInput, newItemLabel.firstChild); 141 // Append input wrapped into new item. 142 newItem.appendChild(newItemLabel); 143 } else { 144 // Append input no wrapped into new item. 145 newItem.appendChild(newItemInput); 146 } 147 // Append new item into UL list. 148 elem.appendChild(newItem); 149 } 89 150 } 90 151 // Trigger a change event to update related links if required. 91 152 $(elem).trigger('change'); -
django/forms/jinja2/django/forms/widgets/multiple_input.html
diff --git a/django/forms/jinja2/django/forms/widgets/multiple_input.html b/django/forms/jinja2/django/forms/widgets/multiple_input.html index be3d449..324f495 100644
a b 1 {% set id = widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %} >{% for group, options, index in widget.optgroups %}{% if group %}1 {% set id = widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %} data-wrap-label="{{ wrap_label|lower }}" data-multiple="{{ multiple|lower }}">{% for group, options, index in widget.optgroups %}{% if group %} 2 2 <li>{{ group }}<ul{% if id %} id="{{ id }}_{{ index }}{% endif %}">{% endif %}{% for widget in options %} 3 3 <li>{% include widget.template_name %}</li>{% endfor %}{% if group %} 4 4 </ul></li>{% endif %}{% endfor %} -
django/forms/templates/django/forms/widgets/multiple_input.html
diff --git a/django/forms/templates/django/forms/widgets/multiple_input.html b/django/forms/templates/django/forms/widgets/multiple_input.html index 60282ff..55881ba 100644
a b 1 {% with id=widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %} >{% for group, options, index in widget.optgroups %}{% if group %}1 {% with id=widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %} data-wrap-label="{{ wrap_label|lower }}" data-multiple="{{ multiple|lower }}">{% for group, options, index in widget.optgroups %}{% if group %} 2 2 <li>{{ group }}<ul{% if id %} id="{{ id }}_{{ index }}{% endif %}">{% endif %}{% for option in options %} 3 3 <li>{% include option.template_name with widget=option %}</li>{% endfor %}{% if group %} 4 4 </ul></li>{% endif %}{% endfor %} -
django/forms/widgets.py
diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 4f028d3..5aed91a 100644
a b class ChoiceWidget(Widget): 626 626 context = super(ChoiceWidget, self).get_context(name, value, attrs) 627 627 context['widget']['optgroups'] = self.optgroups(name, context['widget']['value'], attrs) 628 628 context['wrap_label'] = True 629 context['multiple'] = self.allow_multiple_selected 629 630 return context 630 631 631 632 def id_for_label(self, id_, index='0'): -
js_tests/admin/RelatedObjectLookups.test.js
diff --git a/js_tests/admin/RelatedObjectLookups.test.js b/js_tests/admin/RelatedObjectLookups.test.js index 9ec1eed..04ad8bf 100644
a b 3 3 /* eslint global-strict: 0, strict: 0 */ 4 4 'use strict'; 5 5 6 QUnit.module('admin.RelatedObjectLookups'); 6 QUnit.module('admin.RelatedObjectLookups', { 7 beforeEach: function() { 8 this.win = {name: 'id_teacher', close: function() {}}; 9 } 10 }); 7 11 8 12 QUnit.test('id_to_windowname', function(assert) { 9 13 assert.equal(id_to_windowname('.test'), '__dot__test'); … … QUnit.test('windowname_to_id', function(assert) { 14 18 assert.equal(windowname_to_id('__dot__test'), '.test'); 15 19 assert.equal(windowname_to_id('misc__dash__test'), 'misc-test'); 16 20 }); 21 22 QUnit.test('dismissAddRelatedObjectPopup/Select', function(assert) { 23 var $ = django.jQuery; 24 $('<div class="related-widget-wrapper"></div>').appendTo('#qunit-fixture'); 25 $('<select id="id_teacher" name="teacher"></select>').appendTo('div.related-widget-wrapper'); 26 $('<option value="" selected="">---------</option>').appendTo('#id_teacher'); 27 28 dismissAddRelatedObjectPopup(this.win, '1', 'Alex'); 29 assert.equal($('#id_teacher').find('option').length, 2); 30 assert.equal($('#id_teacher').find('option').last().text(), 'Alex'); 31 assert.ok($('#id_teacher').find('option').last()[0].selected); 32 33 dismissAddRelatedObjectPopup(this.win, '1', 'Susan'); 34 assert.equal($('#id_teacher').find('option').length, 3); 35 assert.equal($('#id_teacher').find('option').last().text(), 'Susan'); 36 // Only the last new item is marked as checked. 37 assert.equal($('#id_teacher').find('option:selected').length, 1); 38 assert.ok($('#id_teacher').find('option').last()[0].selected); 39 }); 40 41 QUnit.test('dismissAddRelatedObjectPopup/SelectMultiple', function(assert) { 42 var $ = django.jQuery; 43 $('<div class="related-widget-wrapper"></div>').appendTo('#qunit-fixture'); 44 $('<select multiple="multiple" id="id_teacher" name="teacher"></select>').appendTo('div.related-widget-wrapper'); 45 46 dismissAddRelatedObjectPopup(this.win, '1', 'Alex'); 47 assert.equal($('#id_teacher').find('option').length, 1); 48 assert.equal($('#id_teacher').find('option').first().text(), 'Alex'); 49 assert.ok($('#id_teacher').find('option').first()[0].selected); 50 51 dismissAddRelatedObjectPopup(this.win, '2', 'Susan'); 52 assert.equal($('#id_teacher').find('option').length, 2); 53 assert.equal($('#id_teacher').find('option').last().text(), 'Susan'); 54 // All new items are marked as checked. 55 assert.equal($('#id_teacher').find('option:selected').length, 2); 56 assert.ok($('#id_teacher').find('option').first()[0].selected); 57 assert.ok($('#id_teacher').find('option').last()[0].selected); 58 }); 59 60 QUnit.test('dismissAddRelatedObjectPopup/TextInput', function(assert) { 61 var $ = django.jQuery; 62 $('<div class="related-widget-wrapper"></div>').appendTo('#qunit-fixture'); 63 $('<input id="id_teacher" name="teacher" type="text" value="">').appendTo('div.related-widget-wrapper'); 64 65 dismissAddRelatedObjectPopup(this.win, '1', 'Alex'); 66 assert.equal($('#id_teacher').val(), '1'); 67 68 dismissAddRelatedObjectPopup(this.win, '2', 'Susan'); 69 assert.equal($('#id_teacher').val(), '2'); 70 }); 71 72 QUnit.test('dismissAddRelatedObjectPopup/TextInput.vManyToManyRawIdAdminField', function(assert) { 73 var $ = django.jQuery; 74 $('<div class="related-widget-wrapper"></div>').appendTo('#qunit-fixture'); 75 $('<input id="id_teacher" name="teacher" type="text" value="" class="vManyToManyRawIdAdminField">').appendTo( 76 'div.related-widget-wrapper' 77 ); 78 79 dismissAddRelatedObjectPopup(this.win, '1', 'Alex'); 80 assert.equal($('#id_teacher').val(), '1'); 81 82 dismissAddRelatedObjectPopup(this.win, '2', 'Susan'); 83 assert.equal($('#id_teacher').val(), '1,2'); 84 }); 85 86 QUnit.test('dismissAddRelatedObjectPopup/RadioSelect', function(assert) { 87 var $ = django.jQuery; 88 $('<div class="related-widget-wrapper"></div>').appendTo('#qunit-fixture'); 89 $('<ul id="id_teacher" data-wrap-label="true" data-multiple="false"></ul>').appendTo('div.related-widget-wrapper'); 90 91 // Add the first item. 92 dismissAddRelatedObjectPopup(this.win, '1', 'Alex'); 93 assert.equal($('#id_teacher').find('li').length, 1); 94 assert.equal($('input#id_teacher_0').length, 1); 95 assert.equal($('input#id_teacher_0').val(), 1); 96 assert.equal($('#id_teacher').find('li').last().find('label').text(), ' Alex'); 97 assert.equal($('#id_teacher').find('input').last()[0].type, "radio"); 98 assert.ok($('#id_teacher').find('input').last()[0].checked); 99 100 // Add the other item. 101 dismissAddRelatedObjectPopup(this.win, '2', 'Susan'); 102 assert.equal($('#id_teacher').find('li').length, 2); 103 assert.equal($('input#id_teacher_1').length, 1); 104 assert.equal($('input#id_teacher_1').val(), 2); 105 assert.equal($('#id_teacher').find('li').last().find('label').text(), ' Susan'); 106 assert.equal($('#id_teacher').find('input').last()[0].type, "radio"); 107 // Only the last new item is marked as checked like the select behavior. 108 assert.equal($('#id_teacher').find('input:checked').length, 1); 109 assert.notOk($('#id_teacher').find('input').first()[0].checked); 110 assert.ok($('#id_teacher').find('input').last()[0].checked); 111 }); 112 113 QUnit.test('dismissAddRelatedObjectPopup/CheckboxSelectMultiple', function(assert) { 114 var $ = django.jQuery; 115 $('<div class="related-widget-wrapper"></div>').appendTo('#qunit-fixture'); 116 $('<ul id="id_teacher" data-wrap-label="true" data-multiple="true"></ul>').appendTo('div.related-widget-wrapper'); 117 118 // Add the first item. 119 dismissAddRelatedObjectPopup(this.win, '1', 'Alex'); 120 assert.equal($('#id_teacher').find('li').length, 1); 121 assert.equal($('input#id_teacher_0').length, 1); 122 assert.equal($('input#id_teacher_0').val(), 1); 123 assert.equal($('#id_teacher').find('li').first().find('label').text(), ' Alex'); 124 assert.equal($('#id_teacher').find('input').first()[0].type, "checkbox"); 125 assert.ok($('#id_teacher').find('input').first()[0].checked); 126 127 // Add the other item. 128 dismissAddRelatedObjectPopup(this.win, '2', 'Susan'); 129 assert.equal($('#id_teacher').find('li').length, 2); 130 assert.equal($('input#id_teacher_1').length, 1); 131 assert.equal($('input#id_teacher_1').val(), 2); 132 assert.equal($('#id_teacher').find('li').last().find('label').text(), ' Susan'); 133 assert.equal($('#id_teacher').find('input').last()[0].type, "checkbox"); 134 // All new items are marked as checked like the select multiple behavior. 135 assert.equal($('#id_teacher').find('input:checked').length, 2); 136 assert.ok($('#id_teacher').find('input').first()[0].checked); 137 assert.ok($('#id_teacher').find('input').last()[0].checked); 138 }); 139 -
tests/admin_widgets/models.py
diff --git a/tests/admin_widgets/models.py b/tests/admin_widgets/models.py index 274c36e..9b3ed2b 100644
a b class Profile(models.Model): 163 163 164 164 def __str__(self): 165 165 return self.user.username 166 167 168 @python_2_unicode_compatible 169 class Manager(models.Model): 170 name = models.CharField(max_length=255) 171 172 def __str__(self): 173 return self.name 174 175 176 @python_2_unicode_compatible 177 class Team(models.Model): 178 name = models.CharField(max_length=255) 179 team_manager = models.ForeignKey(Manager, models.CASCADE, null=True, blank=True) 180 181 def __str__(self): 182 return self.name 183 184 185 @python_2_unicode_compatible 186 class City(models.Model): 187 name = models.CharField(max_length=255) 188 teams = models.ManyToManyField(Team) 189 190 def __str__(self): 191 return self.name 192 193 194 @python_2_unicode_compatible 195 class Player(models.Model): 196 """ 197 This model will be used to test ForeignKey widget relation field as 198 RadioSelect in RelatedFieldWidgetSeleniumTests, the default widget 199 will be overwritten in the test admin file. 200 """ 201 name = models.CharField(max_length=255) 202 team = models.ForeignKey(Team, models.CASCADE, null=True, blank=True) 203 204 def __str__(self): 205 return self.name 206 207 208 @python_2_unicode_compatible 209 class Fan(models.Model): 210 """ 211 This model will be used to test ManyToMany widget relation field as 212 CheckboxSelectMultiple in RelatedFieldWidgetSeleniumTests, the default 213 widget will be overwritten in the test admin file. 214 """ 215 name = models.CharField(max_length=255) 216 teams = models.ManyToManyField(Team) 217 218 def __str__(self): 219 return self.name -
tests/admin_widgets/tests.py
diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index b74df4e..c54189f 100644
a b from django.urls import reverse 23 23 from django.utils import six, translation 24 24 25 25 from .models import ( 26 Advisor, Album, Band, Bee, Car, C ompany, Event, Honeycomb, Individual,27 Inventory, M ember, MyFileField, Profile, School, Student,26 Advisor, Album, Band, Bee, Car, City, Company, Event, Fan, Honeycomb, Individual, 27 Inventory, Manager, Member, MyFileField, Player, Profile, School, Student, Team, 28 28 ) 29 29 from .widgetadmin import site as widget_admin_site 30 30 … … class RelatedFieldWidgetSeleniumTests(AdminWidgetSeleniumTestCase): 1294 1294 profiles = Profile.objects.all() 1295 1295 self.assertEqual(len(profiles), 1) 1296 1296 self.assertEqual(profiles[0].user.username, username_value) 1297 1298 def test_ForeignKey_as_Select(self): 1299 self.admin_login(username='super', password='secret', login_url='/') 1300 self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_team_add')) 1301 1302 main_window = self.selenium.current_window_handle 1303 # Only an empty option in the Select 1304 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_team_manager option')), 1) 1305 1306 # Click the Add Manager button to add new 1307 self.selenium.find_element_by_id('add_id_team_manager').click() 1308 self.wait_for_popup() 1309 self.selenium.switch_to.window('id_team_manager') 1310 1311 manager_name_field = self.selenium.find_element_by_id('id_name') 1312 manager_name_field.send_keys('Martin') 1313 1314 save_button_css_selector = '.submit-row > input[type=submit]' 1315 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1316 self.selenium.switch_to.window(main_window) 1317 1318 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_team_manager option')), 2) 1319 new_manager = Manager.objects.get(pk=1) 1320 self.assertEqual(new_manager.name, 'Martin') 1321 new_option_selector = '#id_team_manager option[value="%d"]' % new_manager.pk 1322 self.assertTrue(self.selenium.find_element_by_css_selector(new_option_selector).get_attribute('selected')) 1323 1324 # Click the Add Manager button to add other 1325 self.selenium.find_element_by_id('add_id_team_manager').click() 1326 self.wait_for_popup() 1327 self.selenium.switch_to.window('id_team_manager') 1328 1329 manager_name_field = self.selenium.find_element_by_id('id_name') 1330 manager_name_field.send_keys('Joe') 1331 1332 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1333 self.selenium.switch_to.window(main_window) 1334 1335 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_team_manager option')), 3) 1336 new_manager = Manager.objects.get(pk=2) 1337 self.assertEqual(new_manager.name, 'Joe') 1338 new_option_selector = '#id_team_manager option[value="%d"]' % new_manager.pk 1339 self.assertTrue(self.selenium.find_element_by_css_selector(new_option_selector).get_attribute('selected')) 1340 1341 # Go ahead and submit the form to make sure it works 1342 team_name_field = self.selenium.find_element_by_id('id_name') 1343 team_name_field.send_keys('Blue Jays') 1344 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1345 self.wait_for_text('li.success', 'The team "Blue Jays" was added successfully.') 1346 teams = Team.objects.all() 1347 self.assertEqual(len(teams), 1) 1348 # 'Joe' match because was the last selected Manager 1349 self.assertEqual(teams[0].team_manager.name, 'Joe') 1350 1351 def test_ManyToMany_as_SelectMultiple(self): 1352 self.admin_login(username='super', password='secret', login_url='/') 1353 self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_city_add')) 1354 1355 main_window = self.selenium.current_window_handle 1356 1357 # Click the Add Team button to add new 1358 self.selenium.find_element_by_id('add_id_teams').click() 1359 self.wait_for_popup() 1360 self.selenium.switch_to.window('id_teams') 1361 1362 team_name_field = self.selenium.find_element_by_id('id_name') 1363 team_name_field.send_keys('Cubs') 1364 1365 save_button_css_selector = '.submit-row > input[type=submit]' 1366 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1367 self.selenium.switch_to.window(main_window) 1368 1369 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_teams option')), 1) 1370 new_team = Team.objects.get(name='Cubs') 1371 new_option_selector = '#id_teams option[value="%d"]' % new_team.pk 1372 self.assertTrue(self.selenium.find_element_by_css_selector(new_option_selector).get_attribute('selected')) 1373 1374 # Click the Add Team button to add other 1375 self.selenium.find_element_by_id('add_id_teams').click() 1376 self.wait_for_popup() 1377 self.selenium.switch_to.window('id_teams') 1378 1379 team_name_field = self.selenium.find_element_by_id('id_name') 1380 team_name_field.send_keys('White Sox') 1381 1382 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1383 self.selenium.switch_to.window(main_window) 1384 1385 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_teams option')), 2) 1386 new_team = Team.objects.get(name='White Sox') 1387 new_option_selector = '#id_teams option[value="%d"]' % new_team.pk 1388 self.assertTrue(self.selenium.find_element_by_css_selector(new_option_selector).get_attribute('selected')) 1389 1390 # Go ahead and submit the form to make sure it works 1391 city_name_field = self.selenium.find_element_by_id('id_name') 1392 city_name_field.send_keys('Chicago') 1393 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1394 self.wait_for_text('li.success', 'The city "Chicago" was added successfully.') 1395 cities = City.objects.all() 1396 self.assertEqual(len(cities), 1) 1397 self.assertEqual(cities[0].name, 'Chicago') 1398 teams = cities[0].teams.all() 1399 self.assertEqual(len(teams), 2) 1400 self.assertListEqual([t.name for t in teams], ['Cubs', 'White Sox']) 1401 1402 def test_ForeignKey_as_RadioSelect(self): 1403 self.admin_login(username='super', password='secret', login_url='/') 1404 self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_player_add')) 1405 1406 main_window = self.selenium.current_window_handle 1407 # Only an empty option in the RadioSelect 1408 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_team li')), 1) 1409 1410 # Click the Add Team button to add new 1411 self.selenium.find_element_by_id('add_id_team').click() 1412 self.wait_for_popup() 1413 self.selenium.switch_to.window('id_team') 1414 1415 team_name_field = self.selenium.find_element_by_id('id_name') 1416 team_name_field.send_keys('Cardinals') 1417 1418 save_button_css_selector = '.submit-row > input[type=submit]' 1419 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1420 self.selenium.switch_to.window(main_window) 1421 1422 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_team li')), 2) 1423 new_team = Team.objects.get(name='Cardinals') 1424 new_input_selector = '#id_team li input[value="%d"]' % new_team.pk 1425 self.assertTrue(self.selenium.find_element_by_css_selector(new_input_selector).get_attribute('checked')) 1426 1427 # Click the Add Team button to add other 1428 self.selenium.find_element_by_id('add_id_team').click() 1429 self.wait_for_popup() 1430 self.selenium.switch_to.window('id_team') 1431 1432 team_name_field = self.selenium.find_element_by_id('id_name') 1433 team_name_field.send_keys('Red Sox') 1434 1435 save_button_css_selector = '.submit-row > input[type=submit]' 1436 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1437 self.selenium.switch_to.window(main_window) 1438 1439 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_team li')), 3) 1440 new_team = Team.objects.get(name='Red Sox') 1441 new_input_selector = '#id_team li input[value="%d"]' % new_team.pk 1442 self.assertTrue(self.selenium.find_element_by_css_selector(new_input_selector).get_attribute('checked')) 1443 1444 # Go ahead and submit the form to make sure it works 1445 player_name_field = self.selenium.find_element_by_id('id_name') 1446 player_name_field.send_keys('David') 1447 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1448 self.wait_for_text('li.success', 'The player "David" was added successfully.') 1449 player = Player.objects.all() 1450 self.assertEqual(len(player), 1) 1451 # 'Red Sox' match because was the last selected Team 1452 self.assertEqual(player[0].team.name, 'Red Sox') 1453 1454 def test_ManyToMany_as_CheckboxSelectMultiple(self): 1455 self.admin_login(username='super', password='secret', login_url='/') 1456 self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_fan_add')) 1457 1458 main_window = self.selenium.current_window_handle 1459 1460 # Click the Add Team button to add new 1461 self.selenium.find_element_by_id('add_id_teams').click() 1462 self.wait_for_popup() 1463 self.selenium.switch_to.window('id_teams') 1464 1465 team_name_field = self.selenium.find_element_by_id('id_name') 1466 team_name_field.send_keys('Cubs') 1467 1468 save_button_css_selector = '.submit-row > input[type=submit]' 1469 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1470 self.selenium.switch_to.window(main_window) 1471 1472 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_teams li')), 1) 1473 new_team = Team.objects.get(name='Cubs') 1474 new_input_selector = '#id_teams li input[value="%d"]' % new_team.pk 1475 self.assertTrue(self.selenium.find_element_by_css_selector(new_input_selector).get_attribute('checked')) 1476 1477 # Click the Add Team button to add other 1478 self.selenium.find_element_by_id('add_id_teams').click() 1479 self.wait_for_popup() 1480 self.selenium.switch_to.window('id_teams') 1481 1482 team_name_field = self.selenium.find_element_by_id('id_name') 1483 team_name_field.send_keys('White Sox') 1484 1485 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1486 self.selenium.switch_to.window(main_window) 1487 1488 self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_teams li')), 2) 1489 new_team = Team.objects.get(name='White Sox') 1490 new_input_selector = '#id_teams li input[value="%d"]' % new_team.pk 1491 self.assertTrue(self.selenium.find_element_by_css_selector(new_input_selector).get_attribute('checked')) 1492 1493 # Go ahead and submit the form to make sure it works 1494 fan_name_field = self.selenium.find_element_by_id('id_name') 1495 fan_name_field.send_keys('John') 1496 self.selenium.find_element_by_css_selector(save_button_css_selector).click() 1497 self.wait_for_text('li.success', 'The fan "John" was added successfully.') 1498 fans = Fan.objects.all() 1499 self.assertEqual(len(fans), 1) 1500 self.assertEqual(fans[0].name, 'John') 1501 teams = fans[0].teams.all() 1502 self.assertEqual(len(teams), 2) 1503 self.assertListEqual([t.name for t in teams], ['Cubs', 'White Sox']) -
tests/admin_widgets/widgetadmin.py
diff --git a/tests/admin_widgets/widgetadmin.py b/tests/admin_widgets/widgetadmin.py index a03e044..235140f 100644
a b 1 from django import forms 1 2 from django.contrib import admin 3 from django.forms import CheckboxSelectMultiple, RadioSelect 2 4 3 5 from .models import ( 4 Advisor, Album, Band, Bee, Car, CarTire, Event, Inventory, Member, Profile,5 School, User,6 Advisor, Album, Band, Bee, Car, CarTire, City, Event, Fan, Inventory, 7 Manager, Member, Player, Profile, School, Team, User, 6 8 ) 7 9 8 10 … … class SchoolAdmin(admin.ModelAdmin): 37 39 filter_horizontal = ('alumni',) 38 40 39 41 42 class PlayerForm(forms.ModelForm): 43 44 class Meta: 45 model = Player 46 fields = '__all__' 47 widgets = {'team': RadioSelect} 48 49 50 class PlayerAdmin(admin.ModelAdmin): 51 form = PlayerForm 52 53 54 class FanForm(forms.ModelForm): 55 56 class Meta: 57 model = Fan 58 fields = '__all__' 59 widgets = {'teams': CheckboxSelectMultiple} 60 61 62 class FanAdmin(admin.ModelAdmin): 63 form = FanForm 64 65 40 66 site = WidgetAdmin(name='widget-admin') 41 67 42 68 site.register(User) … … site.register(Advisor) 57 83 site.register(School, SchoolAdmin) 58 84 59 85 site.register(Profile) 86 87 site.register(Team) 88 site.register(Manager) 89 site.register(City) 90 site.register(Player, PlayerAdmin) 91 site.register(Fan, FanAdmin) -
tests/forms_tests/tests/test_forms.py
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py index 2b93575..bcfe74a 100644
a b class FormsTestCase(SimpleTestCase): 583 583 language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=RadioSelect) 584 584 585 585 f = FrameworkForm(auto_id=False) 586 self.assertHTMLEqual(str(f['language']), """<ul >586 self.assertHTMLEqual(str(f['language']), """<ul data-wrap-label="true" data-multiple="false"> 587 587 <li><label><input type="radio" name="language" value="P" required /> Python</label></li> 588 588 <li><label><input type="radio" name="language" value="J" required /> Java</label></li> 589 589 </ul>""") 590 590 self.assertHTMLEqual(f.as_table(), """<tr><th>Name:</th><td><input type="text" name="name" required /></td></tr> 591 <tr><th>Language:</th><td><ul >591 <tr><th>Language:</th><td><ul data-wrap-label="true" data-multiple="false"> 592 592 <li><label><input type="radio" name="language" value="P" required /> Python</label></li> 593 593 <li><label><input type="radio" name="language" value="J" required /> Java</label></li> 594 594 </ul></td></tr>""") 595 595 self.assertHTMLEqual(f.as_ul(), """<li>Name: <input type="text" name="name" required /></li> 596 <li>Language: <ul >596 <li>Language: <ul data-wrap-label="true" data-multiple="false"> 597 597 <li><label><input type="radio" name="language" value="P" required /> Python</label></li> 598 598 <li><label><input type="radio" name="language" value="J" required /> Java</label></li> 599 599 </ul></li>""") … … class FormsTestCase(SimpleTestCase): 604 604 f = FrameworkForm(auto_id='id_%s') 605 605 self.assertHTMLEqual( 606 606 str(f['language']), 607 """<ul id="id_language" >607 """<ul id="id_language" data-wrap-label="true" data-multiple="false"> 608 608 <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required /> 609 609 Python</label></li> 610 610 <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required /> … … Java</label></li> 618 618 self.assertHTMLEqual( 619 619 f.as_table(), 620 620 """<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name" required /></td></tr> 621 <tr><th><label for="id_language_0">Language:</label></th><td><ul id="id_language" >621 <tr><th><label for="id_language_0">Language:</label></th><td><ul id="id_language" data-wrap-label="true" data-multiple="false"> 622 622 <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required /> 623 623 Python</label></li> 624 624 <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required /> … … Java</label></li> 628 628 self.assertHTMLEqual( 629 629 f.as_ul(), 630 630 """<li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" required /></li> 631 <li><label for="id_language_0">Language:</label> <ul id="id_language" >631 <li><label for="id_language_0">Language:</label> <ul id="id_language" data-wrap-label="true" data-multiple="false"> 632 632 <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required /> 633 633 Python</label></li> 634 634 <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required /> … … Java</label></li> 638 638 self.assertHTMLEqual( 639 639 f.as_p(), 640 640 """<p><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" required /></p> 641 <p><label for="id_language_0">Language:</label> <ul id="id_language" >641 <p><label for="id_language_0">Language:</label> <ul id="id_language" data-wrap-label="true" data-multiple="false"> 642 642 <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required /> 643 643 Python</label></li> 644 644 <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required /> … … Java</label></li> 851 851 ) 852 852 853 853 f = SongForm(auto_id=False) 854 self.assertHTMLEqual(str(f['composers']), """<ul >854 self.assertHTMLEqual(str(f['composers']), """<ul data-wrap-label="true" data-multiple="true"> 855 855 <li><label><input type="checkbox" name="composers" value="J" /> John Lennon</label></li> 856 856 <li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li> 857 857 </ul>""") 858 858 f = SongForm({'composers': ['J']}, auto_id=False) 859 self.assertHTMLEqual(str(f['composers']), """<ul >859 self.assertHTMLEqual(str(f['composers']), """<ul data-wrap-label="true" data-multiple="true"> 860 860 <li><label><input checked type="checkbox" name="composers" value="J" /> John Lennon</label></li> 861 861 <li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li> 862 862 </ul>""") 863 863 f = SongForm({'composers': ['J', 'P']}, auto_id=False) 864 self.assertHTMLEqual(str(f['composers']), """<ul >864 self.assertHTMLEqual(str(f['composers']), """<ul data-wrap-label="true" data-multiple="true"> 865 865 <li><label><input checked type="checkbox" name="composers" value="J" /> John Lennon</label></li> 866 866 <li><label><input checked type="checkbox" name="composers" value="P" /> Paul McCartney</label></li> 867 867 </ul>""") … … Java</label></li> 886 886 f = SongForm(auto_id='%s_id') 887 887 self.assertHTMLEqual( 888 888 str(f['composers']), 889 """<ul id="composers_id" >889 """<ul id="composers_id" data-wrap-label="true" data-multiple="true"> 890 890 <li><label for="composers_id_0"> 891 891 <input type="checkbox" name="composers" value="J" id="composers_id_0" /> John Lennon</label></li> 892 892 <li><label for="composers_id_1"> -
tests/forms_tests/tests/test_i18n.py
diff --git a/tests/forms_tests/tests/test_i18n.py b/tests/forms_tests/tests/test_i18n.py index 56225e0..9f83295 100644
a b class FormsI18nTests(SimpleTestCase): 59 59 self.assertHTMLEqual( 60 60 f.as_p(), 61 61 '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label>' 62 '<ul id="id_somechoice" >\n'62 '<ul id="id_somechoice" data-wrap-label="true" data-multiple="false">\n' 63 63 '<li><label for="id_somechoice_0">' 64 64 '<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required /> ' 65 65 'En tied\xe4</label></li>\n' … … class FormsI18nTests(SimpleTestCase): 79 79 '\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c' 80 80 '\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n' 81 81 '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label>' 82 ' <ul id="id_somechoice">\n<li><label for="id_somechoice_0">' 82 ' <ul id="id_somechoice" data-wrap-label="true" data-multiple="false">\n' 83 '<li><label for="id_somechoice_0">' 83 84 '<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required /> ' 84 85 'En tied\xe4</label></li>\n' 85 86 '<li><label for="id_somechoice_1">' -
tests/forms_tests/widget_tests/test_checkboxselectmultiple.py
diff --git a/tests/forms_tests/widget_tests/test_checkboxselectmultiple.py b/tests/forms_tests/widget_tests/test_checkboxselectmultiple.py index a92e553..db42521 100644
a b class CheckboxSelectMultipleTest(WidgetTest): 9 9 10 10 def test_render_value(self): 11 11 self.check_html(self.widget(choices=self.beatles), 'beatles', ['J'], html=( 12 """<ul >12 """<ul data-wrap-label="true" data-multiple="true"> 13 13 <li><label><input checked type="checkbox" name="beatles" value="J" /> John</label></li> 14 14 <li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 15 15 <li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> … … class CheckboxSelectMultipleTest(WidgetTest): 19 19 20 20 def test_render_value_multiple(self): 21 21 self.check_html(self.widget(choices=self.beatles), 'beatles', ['J', 'P'], html=( 22 """<ul >22 """<ul data-wrap-label="true" data-multiple="true"> 23 23 <li><label><input checked type="checkbox" name="beatles" value="J" /> John</label></li> 24 24 <li><label><input checked type="checkbox" name="beatles" value="P" /> Paul</label></li> 25 25 <li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> … … class CheckboxSelectMultipleTest(WidgetTest): 32 32 If the value is None, none of the options are selected. 33 33 """ 34 34 self.check_html(self.widget(choices=self.beatles), 'beatles', None, html=( 35 """<ul >35 """<ul data-wrap-label="true" data-multiple="true"> 36 36 <li><label><input type="checkbox" name="beatles" value="J" /> John</label></li> 37 37 <li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 38 38 <li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> … … class CheckboxSelectMultipleTest(WidgetTest): 47 47 ('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))), 48 48 ) 49 49 html = """ 50 <ul id="media" >50 <ul id="media" data-wrap-label="true" data-multiple="true"> 51 51 <li> 52 52 <label for="media_0"><input id="media_0" name="nestchoice" type="checkbox" value="unknown" /> Unknown</label> 53 53 </li> … … class CheckboxSelectMultipleTest(WidgetTest): 84 84 """ 85 85 choices = [('a', 'A'), ('b', 'B'), ('c', 'C')] 86 86 html = """ 87 <ul id="abc" >87 <ul id="abc" data-wrap-label="true" data-multiple="true"> 88 88 <li> 89 89 <label for="abc_0"><input checked type="checkbox" name="letters" value="a" id="abc_0" /> A</label> 90 90 </li> … … class CheckboxSelectMultipleTest(WidgetTest): 102 102 """ 103 103 widget = CheckboxSelectMultiple(attrs={'id': 'abc'}, choices=[('a', 'A'), ('b', 'B'), ('c', 'C')]) 104 104 html = """ 105 <ul id="abc" >105 <ul id="abc" data-wrap-label="true" data-multiple="true"> 106 106 <li> 107 107 <label for="abc_0"><input checked type="checkbox" name="letters" value="a" id="abc_0" /> A</label> 108 108 </li> -
tests/forms_tests/widget_tests/test_radioselect.py
diff --git a/tests/forms_tests/widget_tests/test_radioselect.py b/tests/forms_tests/widget_tests/test_radioselect.py index fea26ce..df1cff5 100644
a b class RadioSelectTest(WidgetTest): 8 8 9 9 def test_render(self): 10 10 self.check_html(self.widget(choices=self.beatles), 'beatle', 'J', html=( 11 """<ul >11 """<ul data-wrap-label="true" data-multiple="false"> 12 12 <li><label><input checked type="radio" name="beatle" value="J" /> John</label></li> 13 13 <li><label><input type="radio" name="beatle" value="P" /> Paul</label></li> 14 14 <li><label><input type="radio" name="beatle" value="G" /> George</label></li> … … class RadioSelectTest(WidgetTest): 23 23 ('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))), 24 24 ) 25 25 html = """ 26 <ul id="media" >26 <ul id="media" data-wrap-label="true" data-multiple="false"> 27 27 <li> 28 28 <label for="media_0"><input id="media_0" name="nestchoice" type="radio" value="unknown" /> Unknown</label> 29 29 </li> … … class RadioSelectTest(WidgetTest): 55 55 """ 56 56 widget = RadioSelect(attrs={'id': 'foo'}, choices=self.beatles) 57 57 html = """ 58 <ul id="foo" >58 <ul id="foo" data-wrap-label="true" data-multiple="false"> 59 59 <li> 60 60 <label for="foo_0"><input checked type="radio" id="foo_0" value="J" name="beatle" /> John</label> 61 61 </li> … … class RadioSelectTest(WidgetTest): 72 72 inputs. 73 73 """ 74 74 html = """ 75 <ul id="bar" >75 <ul id="bar" data-wrap-label="true" data-multiple="false"> 76 76 <li> 77 77 <label for="bar_0"><input checked type="radio" id="bar_0" value="J" name="beatle" /> John</label> 78 78 </li>