# -*- coding: utf-8 -*- from __future__ import unicode_literals import copy import datetime import warnings from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase from django.core.files.uploadedfile import SimpleUploadedFile from django.core.urlresolvers import reverse from django.forms import ( BooleanField, CheckboxInput, CheckboxSelectMultiple, ChoiceField, ClearableFileInput, DateInput, DateTimeField, DateTimeInput, FileInput, Form, HiddenInput, MultipleHiddenInput, MultiWidget, NullBooleanSelect, PasswordInput, RadioSelect, Select, SelectMultiple, SplitDateTimeWidget, Textarea, TextInput, TimeInput, ) from django.forms.widgets import RadioFieldRenderer from django.utils.deprecation import RemovedInDjango19Warning from django.utils.safestring import mark_safe from django.utils import six from django.utils.translation import activate, deactivate, override from django.test import TestCase, override_settings from django.utils.encoding import python_2_unicode_compatible, force_text from ..models import Article class FormsWidgetTestCase(TestCase): # Each Widget class corresponds to an HTML form widget. A Widget knows how to # render itself, given a field name and some data. Widgets don't perform # validation. def test_textinput(self): w = TextInput() self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', None), '') self.assertHTMLEqual(w.render('email', 'test@example.com'), '') self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '') self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '') self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '') # You can also pass 'attrs' to the constructor: w = TextInput(attrs={'class': 'fun', 'type': 'email'}) self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', 'foo@example.com'), '') # 'attrs' passed to render() get precedence over those passed to the constructor: w = TextInput(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '') # 'attrs' can be safe-strings if needed) w = TextInput(attrs={'onBlur': mark_safe("function('foo')")}) self.assertHTMLEqual(w.render('email', ''), '') def test_passwordinput(self): w = PasswordInput() self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', None), '') self.assertHTMLEqual(w.render('email', 'secret'), '') # The render_value argument lets you specify whether the widget should render # its value. For security reasons, this is off by default. w = PasswordInput(render_value=True) self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', None), '') self.assertHTMLEqual(w.render('email', 'test@example.com'), '') self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '') self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '') # You can also pass 'attrs' to the constructor: w = PasswordInput(attrs={'class': 'fun'}, render_value=True) self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', 'foo@example.com'), '') # 'attrs' passed to render() get precedence over those passed to the constructor: w = PasswordInput(attrs={'class': 'pretty'}, render_value=True) self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '') self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '') def test_hiddeninput(self): w = HiddenInput() self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', None), '') self.assertHTMLEqual(w.render('email', 'test@example.com'), '') self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '') self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '') # You can also pass 'attrs' to the constructor: w = HiddenInput(attrs={'class': 'fun'}) self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', 'foo@example.com'), '') # 'attrs' passed to render() get precedence over those passed to the constructor: w = HiddenInput(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '') self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '') # 'attrs' passed to render() get precedence over those passed to the constructor: w = HiddenInput(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '') # Boolean values are rendered to their string forms ("True" and "False"). w = HiddenInput() self.assertHTMLEqual(w.render('get_spam', False), '') self.assertHTMLEqual(w.render('get_spam', True), '') def test_multiplehiddeninput(self): w = MultipleHiddenInput() self.assertHTMLEqual(w.render('email', []), '') self.assertHTMLEqual(w.render('email', None), '') self.assertHTMLEqual(w.render('email', ['test@example.com']), '') self.assertHTMLEqual(w.render('email', ['some "quoted" & ampersanded value']), '') self.assertHTMLEqual(w.render('email', ['test@example.com', 'foo@example.com']), '\n') self.assertHTMLEqual(w.render('email', ['test@example.com'], attrs={'class': 'fun'}), '') self.assertHTMLEqual(w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'}), '\n') # You can also pass 'attrs' to the constructor: w = MultipleHiddenInput(attrs={'class': 'fun'}) self.assertHTMLEqual(w.render('email', []), '') self.assertHTMLEqual(w.render('email', ['foo@example.com']), '') self.assertHTMLEqual(w.render('email', ['foo@example.com', 'test@example.com']), '\n') # 'attrs' passed to render() get precedence over those passed to the constructor: w = MultipleHiddenInput(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('email', ['foo@example.com'], attrs={'class': 'special'}), '') self.assertHTMLEqual(w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'}), '') # 'attrs' passed to render() get precedence over those passed to the constructor: w = MultipleHiddenInput(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('email', ['foo@example.com'], attrs={'class': 'special'}), '') # Each input gets a separate ID. w = MultipleHiddenInput() self.assertHTMLEqual(w.render('letters', list('abc'), attrs={'id': 'hideme'}), '\n\n') def test_fileinput(self): # FileInput widgets don't ever show the value, because the old value is of no use # if you are updating the form or if the provided file generated an error. w = FileInput() self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', None), '') self.assertHTMLEqual(w.render('email', 'test@example.com'), '') self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '') self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '') # You can also pass 'attrs' to the constructor: w = FileInput(attrs={'class': 'fun'}) self.assertHTMLEqual(w.render('email', ''), '') self.assertHTMLEqual(w.render('email', 'foo@example.com'), '') self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '') def test_textarea(self): w = Textarea() self.assertHTMLEqual(w.render('msg', ''), '') self.assertHTMLEqual(w.render('msg', None), '') self.assertHTMLEqual(w.render('msg', 'value'), '') self.assertHTMLEqual(w.render('msg', 'some "quoted" & ampersanded value'), '') self.assertHTMLEqual(w.render('msg', mark_safe('pre "quoted" value')), '') self.assertHTMLEqual(w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20}), '') # You can also pass 'attrs' to the constructor: w = Textarea(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('msg', ''), '') self.assertHTMLEqual(w.render('msg', 'example'), '') # 'attrs' passed to render() get precedence over those passed to the constructor: w = Textarea(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('msg', '', attrs={'class': 'special'}), '') self.assertHTMLEqual(w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '') def test_checkboxinput(self): w = CheckboxInput() self.assertHTMLEqual(w.render('is_cool', ''), '') self.assertHTMLEqual(w.render('is_cool', None), '') self.assertHTMLEqual(w.render('is_cool', False), '') self.assertHTMLEqual(w.render('is_cool', True), '') # Using any value that's not in ('', None, False, True) will check the checkbox # and set the 'value' attribute. self.assertHTMLEqual(w.render('is_cool', 'foo'), '') self.assertHTMLEqual(w.render('is_cool', False, attrs={'class': 'pretty'}), '') # regression for #17114 self.assertHTMLEqual(w.render('is_cool', 0), '') self.assertHTMLEqual(w.render('is_cool', 1), '') # You can also pass 'attrs' to the constructor: w = CheckboxInput(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('is_cool', ''), '') # 'attrs' passed to render() get precedence over those passed to the constructor: w = CheckboxInput(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('is_cool', '', attrs={'class': 'special'}), '') # You can pass 'check_test' to the constructor. This is a callable that takes the # value and returns True if the box should be checked. w = CheckboxInput(check_test=lambda value: value.startswith('hello')) self.assertHTMLEqual(w.render('greeting', ''), '') self.assertHTMLEqual(w.render('greeting', 'hello'), '') self.assertHTMLEqual(w.render('greeting', 'hello there'), '') self.assertHTMLEqual(w.render('greeting', 'hello & goodbye'), '') # Ticket #17888: calling check_test shouldn't swallow exceptions with self.assertRaises(AttributeError): w.render('greeting', True) # The CheckboxInput widget will return False if the key is not found in the data # dictionary (because HTML form submission doesn't send any result for unchecked # checkboxes). self.assertFalse(w.value_from_datadict({}, {}, 'testing')) value = w.value_from_datadict({'testing': '0'}, {}, 'testing') self.assertIsInstance(value, bool) self.assertTrue(value) def test_select(self): w = Select() self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value is None, none of the options are selected: self.assertHTMLEqual(w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value corresponds to a label (but not to an option value), none of the options are selected: self.assertHTMLEqual(w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # Only one option can be selected, see #8103: self.assertHTMLEqual(w.render('choices', '0', choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """""") # The value is compared to its str(): self.assertHTMLEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """""") self.assertHTMLEqual(w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]), """""") self.assertHTMLEqual(w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]), """""") # The 'choices' argument can be any iterable: from itertools import chain def get_choices(): for i in range(5): yield (i, i) self.assertHTMLEqual(w.render('num', 2, choices=get_choices()), """""") things = ({'id': 1, 'name': 'And Boom'}, {'id': 2, 'name': 'One More Thing!'}) class SomeForm(Form): somechoice = ChoiceField(choices=chain((('', '-' * 9),), [(thing['id'], thing['name']) for thing in things])) f = SomeForm() self.assertHTMLEqual(f.as_table(), '') self.assertHTMLEqual(f.as_table(), '') f = SomeForm({'somechoice': 2}) self.assertHTMLEqual(f.as_table(), '') # You can also pass 'choices' to the constructor: w = Select(choices=[(1, 1), (2, 2), (3, 3)]) self.assertHTMLEqual(w.render('num', 2), """""") # If 'choices' is passed to both the constructor and render(), then they'll both be in the output: self.assertHTMLEqual(w.render('num', 2, choices=[(4, 4), (5, 5)]), """""") # Choices are escaped correctly self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """""") # Unicode choices are correctly rendered as HTML self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '') # If choices is passed to the constructor and is a generator, it can be iterated # over multiple times without getting consumed: w = Select(choices=get_choices()) self.assertHTMLEqual(w.render('num', 2), """""") self.assertHTMLEqual(w.render('num', 3), """""") # Choices can be nested one level in order to create HTML optgroups: w.choices = ( ('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))), ) self.assertHTMLEqual(w.render('nestchoice', None), """""") self.assertHTMLEqual(w.render('nestchoice', 'outer1'), """""") self.assertHTMLEqual(w.render('nestchoice', 'inner1'), """""") def test_nullbooleanselect(self): w = NullBooleanSelect() self.assertTrue(w.render('is_cool', True), """""") self.assertHTMLEqual(w.render('is_cool', False), """""") self.assertHTMLEqual(w.render('is_cool', None), """""") self.assertHTMLEqual(w.render('is_cool', '2'), """""") self.assertHTMLEqual(w.render('is_cool', '3'), """""") def test_selectmultiple(self): w = SelectMultiple() self.assertHTMLEqual(w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") self.assertHTMLEqual(w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") self.assertHTMLEqual(w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value is None, none of the options are selected: self.assertHTMLEqual(w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value corresponds to a label (but not to an option value), none of the options are selected: self.assertHTMLEqual(w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # Multiple options (with the same value) can be selected, see #8103: self.assertHTMLEqual(w.render('choices', ['0'], choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """""") # If multiple values are given, but some of them are not valid, the valid ones are selected: self.assertHTMLEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # The value is compared to its str(): self.assertHTMLEqual(w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]), """""") self.assertHTMLEqual(w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]), """""") self.assertHTMLEqual(w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]), """""") # The 'choices' argument can be any iterable: def get_choices(): for i in range(5): yield (i, i) self.assertHTMLEqual(w.render('nums', [2], choices=get_choices()), """""") # You can also pass 'choices' to the constructor: w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)]) self.assertHTMLEqual(w.render('nums', [2]), """""") # If 'choices' is passed to both the constructor and render(), then they'll both be in the output: self.assertHTMLEqual(w.render('nums', [2], choices=[(4, 4), (5, 5)]), """""") # Choices are escaped correctly self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """""") # Unicode choices are correctly rendered as HTML self.assertHTMLEqual(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '') # Choices can be nested one level in order to create HTML optgroups: w.choices = (('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2')))) self.assertHTMLEqual(w.render('nestchoice', None), """""") self.assertHTMLEqual(w.render('nestchoice', ['outer1']), """""") self.assertHTMLEqual(w.render('nestchoice', ['inner1']), """""") self.assertHTMLEqual(w.render('nestchoice', ['outer1', 'inner2']), """""") def test_radioselect(self): w = RadioSelect() self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value is None, none of the options are checked: self.assertHTMLEqual(w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value corresponds to a label (but not to an option value), none of the options are checked: self.assertHTMLEqual(w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # The value is compared to its str(): self.assertHTMLEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """""") self.assertHTMLEqual(w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]), """""") self.assertHTMLEqual(w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]), """""") # The 'choices' argument can be any iterable: def get_choices(): for i in range(5): yield (i, i) self.assertHTMLEqual(w.render('num', 2, choices=get_choices()), """""") # You can also pass 'choices' to the constructor: w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)]) self.assertHTMLEqual(w.render('num', 2), """""") # If 'choices' is passed to both the constructor and render(), then they'll both be in the output: self.assertHTMLEqual(w.render('num', 2, choices=[(4, 4), (5, 5)]), """""") # RadioSelect uses a RadioFieldRenderer to render the individual radio inputs. # You can manipulate that object directly to customize the way the RadioSelect # is rendered. w = RadioSelect() r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) inp_set1 = [] inp_set2 = [] inp_set3 = [] inp_set4 = [] for inp in r: inp_set1.append(str(inp)) inp_set2.append('%s
' % inp) inp_set3.append('

%s %s

' % (inp.tag(), inp.choice_label)) inp_set4.append('%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())) self.assertHTMLEqual('\n'.join(inp_set1), """ """) self.assertHTMLEqual('\n'.join(inp_set2), """



""") self.assertHTMLEqual('\n'.join(inp_set3), """

John

Paul

George

Ringo

""") self.assertHTMLEqual('\n'.join(inp_set4), """beatle J J John True beatle J P Paul False beatle J G George False beatle J R Ringo False""") # You can create your own custom renderers for RadioSelect to use. class MyRenderer(RadioFieldRenderer): def render(self): return '
\n'.join(six.text_type(choice) for choice in self) w = RadioSelect(renderer=MyRenderer) self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """


""") # Or you can use custom RadioSelect fields that use your custom renderer. class CustomRadioSelect(RadioSelect): renderer = MyRenderer w = CustomRadioSelect() self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """


""") # A RadioFieldRenderer object also allows index access to individual RadioChoiceInput w = RadioSelect() r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) self.assertHTMLEqual(str(r[1]), '') self.assertHTMLEqual(str(r[0]), '') self.assertTrue(r[0].is_checked()) self.assertFalse(r[1].is_checked()) self.assertEqual((r[1].name, r[1].value, r[1].choice_value, r[1].choice_label), ('beatle', 'J', 'P', 'Paul')) with self.assertRaises(IndexError): r[10] # Choices are escaped correctly w = RadioSelect() self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """""") # Unicode choices are correctly rendered as HTML w = RadioSelect() self.assertHTMLEqual(six.text_type(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])), '') # Attributes provided at instantiation are passed to the constituent inputs w = RadioSelect(attrs={'id': 'foo'}) self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # Attributes provided at render-time are passed to the constituent inputs w = RadioSelect() self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id': 'bar'}), """""") def test_nested_choices(self): # Choices can be nested for radio buttons: w = RadioSelect() w.choices = ( ('unknown', 'Unknown'), ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'))), ('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))), ) self.assertHTMLEqual(w.render('nestchoice', 'dvd', attrs={'id': 'media'}), """""") # Choices can be nested for checkboxes: w = CheckboxSelectMultiple() w.choices = ( ('unknown', 'Unknown'), ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'))), ('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))), ) self.assertHTMLEqual(w.render('nestchoice', ('vinyl', 'dvd'), attrs={'id': 'media'}), """""") def test_checkboxselectmultiple(self): w = CheckboxSelectMultiple() self.assertHTMLEqual(w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") self.assertHTMLEqual(w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") self.assertHTMLEqual(w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value is None, none of the options are selected: self.assertHTMLEqual(w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value corresponds to a label (but not to an option value), none of the options are selected: self.assertHTMLEqual(w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If multiple values are given, but some of them are not valid, the valid ones are selected: self.assertHTMLEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # The value is compared to its str(): self.assertHTMLEqual(w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]), """""") self.assertHTMLEqual(w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]), """""") self.assertHTMLEqual(w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]), """""") # The 'choices' argument can be any iterable: def get_choices(): for i in range(5): yield (i, i) self.assertHTMLEqual(w.render('nums', [2], choices=get_choices()), """""") # You can also pass 'choices' to the constructor: w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)]) self.assertHTMLEqual(w.render('nums', [2]), """""") # If 'choices' is passed to both the constructor and render(), then they'll both be in the output: self.assertHTMLEqual(w.render('nums', [2], choices=[(4, 4), (5, 5)]), """""") # Choices are escaped correctly self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """""") # Unicode choices are correctly rendered as HTML self.assertHTMLEqual(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '') # Each input gets a separate ID self.assertHTMLEqual(CheckboxSelectMultiple().render('letters', list('ac'), choices=zip(list('abc'), list('ABC')), attrs={'id': 'abc'}), """""") # Each input gets a separate ID when the ID is passed to the constructor self.assertHTMLEqual(CheckboxSelectMultiple(attrs={'id': 'abc'}).render('letters', list('ac'), choices=zip(list('abc'), list('ABC'))), """""") w = CheckboxSelectMultiple() r = w.get_renderer('abc', 'b', choices=[(c, c.upper()) for c in 'abc']) # You can iterate over the CheckboxFieldRenderer to get individual elements expected = [ '', '', '', ] for output, expected in zip(r, expected): self.assertHTMLEqual(force_text(output), expected) # You can access individual elements self.assertHTMLEqual(force_text(r[1]), '') # Out-of-range errors are propagated with self.assertRaises(IndexError): r[42] def test_subwidget(self): # Each subwidget tag gets a separate ID when the widget has an ID specified self.assertHTMLEqual("\n".join(c.tag() for c in CheckboxSelectMultiple(attrs={'id': 'abc'}).subwidgets('letters', list('ac'), choices=zip(list('abc'), list('ABC')))), """ """) # Each subwidget tag does not get an ID if the widget does not have an ID specified self.assertHTMLEqual("\n".join(c.tag() for c in CheckboxSelectMultiple().subwidgets('letters', list('ac'), choices=zip(list('abc'), list('ABC')))), """ """) # The id_for_label property of the subwidget should return the ID that is used on the subwidget's tag self.assertHTMLEqual("\n".join('' % (c.choice_value, c.id_for_label) for c in CheckboxSelectMultiple(attrs={'id': 'abc'}).subwidgets('letters', [], choices=zip(list('abc'), list('ABC')))), """ """) def test_multi(self): class MyMultiWidget(MultiWidget): def decompress(self, value): if value: return value.split('__') return ['', ''] def format_output(self, rendered_widgets): return '
'.join(rendered_widgets) w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'}))) self.assertHTMLEqual(w.render('name', ['john', 'lennon']), '
') self.assertHTMLEqual(w.render('name', 'john__lennon'), '
') self.assertHTMLEqual(w.render('name', 'john__lennon', attrs={'id': 'foo'}), '
') w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'}) self.assertHTMLEqual(w.render('name', ['john', 'lennon']), '
') # Test needs_multipart_form=True if any widget needs it w = MyMultiWidget(widgets=(TextInput(), FileInput())) self.assertTrue(w.needs_multipart_form) # Test needs_multipart_form=False if no widget needs it w = MyMultiWidget(widgets=(TextInput(), TextInput())) self.assertFalse(w.needs_multipart_form) def test_splitdatetime(self): w = SplitDateTimeWidget() self.assertHTMLEqual(w.render('date', ''), '') self.assertHTMLEqual(w.render('date', None), '') self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '') self.assertHTMLEqual(w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)]), '') # You can also pass 'attrs' to the constructor. In this case, the attrs will be w = SplitDateTimeWidget(attrs={'class': 'pretty'}) self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '') # Use 'date_format' and 'time_format' to change the way a value is displayed. w = SplitDateTimeWidget(date_format='%d/%m/%Y', time_format='%H:%M') self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '') def test_datetimeinput(self): w = DateTimeInput() self.assertHTMLEqual(w.render('date', None), '') d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548) self.assertEqual(str(d), '2007-09-17 12:51:34.482548') # The microseconds are trimmed on display, by default. self.assertHTMLEqual(w.render('date', d), '') self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)), '') self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '') # Use 'format' to change the way a value is displayed. w = DateTimeInput(format='%d/%m/%Y %H:%M', attrs={'type': 'datetime'}) self.assertHTMLEqual(w.render('date', d), '') def test_dateinput(self): w = DateInput() self.assertHTMLEqual(w.render('date', None), '') d = datetime.date(2007, 9, 17) self.assertEqual(str(d), '2007-09-17') self.assertHTMLEqual(w.render('date', d), '') self.assertHTMLEqual(w.render('date', datetime.date(2007, 9, 17)), '') # We should be able to initialize from a unicode value. self.assertHTMLEqual(w.render('date', '2007-09-17'), '') # Use 'format' to change the way a value is displayed. w = DateInput(format='%d/%m/%Y', attrs={'type': 'date'}) self.assertHTMLEqual(w.render('date', d), '') def test_timeinput(self): w = TimeInput() self.assertHTMLEqual(w.render('time', None), '') t = datetime.time(12, 51, 34, 482548) self.assertEqual(str(t), '12:51:34.482548') # The microseconds are trimmed on display, by default. self.assertHTMLEqual(w.render('time', t), '') self.assertHTMLEqual(w.render('time', datetime.time(12, 51, 34)), '') self.assertHTMLEqual(w.render('time', datetime.time(12, 51)), '') # We should be able to initialize from a unicode value. self.assertHTMLEqual(w.render('time', '13:12:11'), '') # Use 'format' to change the way a value is displayed. w = TimeInput(format='%H:%M', attrs={'type': 'time'}) self.assertHTMLEqual(w.render('time', t), '') def test_splithiddendatetime(self): from django.forms.widgets import SplitHiddenDateTimeWidget w = SplitHiddenDateTimeWidget() self.assertHTMLEqual(w.render('date', ''), '') d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548) self.assertHTMLEqual(str(d), '2007-09-17 12:51:34.482548') self.assertHTMLEqual(w.render('date', d), '') self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)), '') self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '') class NullBooleanSelectLazyForm(Form): """Form to test for lazy evaluation. Refs #17190""" bool = BooleanField(widget=NullBooleanSelect()) @override_settings(USE_L10N=True) class FormsI18NWidgetsTestCase(TestCase): def setUp(self): super(FormsI18NWidgetsTestCase, self).setUp() activate('de-at') def tearDown(self): deactivate() super(FormsI18NWidgetsTestCase, self).tearDown() def test_datetimeinput(self): w = DateTimeInput() d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548) self.assertHTMLEqual(w.render('date', d), '') def test_dateinput(self): w = DateInput() d = datetime.date(2007, 9, 17) self.assertHTMLEqual(w.render('date', d), '') def test_timeinput(self): w = TimeInput() t = datetime.time(12, 51, 34, 482548) self.assertHTMLEqual(w.render('time', t), '') def test_datetime_locale_aware(self): w = DateTimeInput() d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548) with self.settings(USE_L10N=False): self.assertHTMLEqual(w.render('date', d), '') with override('es'): self.assertHTMLEqual(w.render('date', d), '') def test_splithiddendatetime(self): from django.forms.widgets import SplitHiddenDateTimeWidget w = SplitHiddenDateTimeWidget() self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '') def test_nullbooleanselect(self): """ Ensure that the NullBooleanSelect widget's options are lazily localized. Refs #17190 """ f = NullBooleanSelectLazyForm() self.assertHTMLEqual(f.fields['bool'].widget.render('id_bool', True), '') class SelectAndTextWidget(MultiWidget): """ MultiWidget subclass """ def __init__(self, choices=[]): widgets = [ RadioSelect(choices=choices), TextInput ] super(SelectAndTextWidget, self).__init__(widgets) def _set_choices(self, choices): """ When choices are set for this widget, we want to pass those along to the Select widget """ self.widgets[0].choices = choices def _get_choices(self): """ The choices for this widget are the Select widget's choices """ return self.widgets[0].choices choices = property(_get_choices, _set_choices) class WidgetTests(TestCase): def test_12048(self): # See ticket #12048. w1 = SelectAndTextWidget(choices=[1, 2, 3]) w2 = copy.deepcopy(w1) w2.choices = [4, 5, 6] # w2 ought to be independent of w1, since MultiWidget ought # to make a copy of its sub-widgets when it is copied. self.assertEqual(w1.choices, [1, 2, 3]) def test_13390(self): # See ticket #13390 class SplitDateForm(Form): field = DateTimeField(widget=SplitDateTimeWidget, required=False) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=RemovedInDjango19Warning) form = SplitDateForm({'field': ''}) self.assertTrue(form.is_valid()) form = SplitDateForm({'field': ['', '']}) self.assertTrue(form.is_valid()) class SplitDateRequiredForm(Form): field = DateTimeField(widget=SplitDateTimeWidget, required=True) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=RemovedInDjango19Warning) form = SplitDateRequiredForm({'field': ''}) self.assertFalse(form.is_valid()) form = SplitDateRequiredForm({'field': ['', '']}) self.assertFalse(form.is_valid()) @override_settings(ROOT_URLCONF='forms_tests.urls') class LiveWidgetTests(AdminSeleniumWebDriverTestCase): available_apps = ['forms_tests'] + AdminSeleniumWebDriverTestCase.available_apps def test_textarea_trailing_newlines(self): """ Test that a roundtrip on a ModelForm doesn't alter the TextField value """ article = Article.objects.create(content="\nTst\n") self.selenium.get('%s%s' % (self.live_server_url, reverse('article_form', args=[article.pk]))) self.selenium.find_element_by_id('submit').submit() article = Article.objects.get(pk=article.pk) # Should be "\nTst\n" after #19251 is fixed self.assertEqual(article.content, "\r\nTst\r\n") @python_2_unicode_compatible class FakeFieldFile(object): """ Quacks like a FieldFile (has a .url and unicode representation), but doesn't require us to care about storages etc. """ url = 'something' def __str__(self): return self.url class ClearableFileInputTests(TestCase): def test_clear_input_renders(self): """ A ClearableFileInput with is_required False and rendered with an initial value that is a file renders a clear checkbox. """ widget = ClearableFileInput() widget.is_required = False self.assertHTMLEqual(widget.render('myfile', FakeFieldFile()), 'Currently: something
Change: ') def test_html_escaped(self): """ A ClearableFileInput should escape name, filename and URL when rendering HTML. Refs #15182. """ @python_2_unicode_compatible class StrangeFieldFile(object): url = "something?chapter=1§=2©=3&lang=en" def __str__(self): return '''something
.jpg''' widget = ClearableFileInput() field = StrangeFieldFile() output = widget.render('my
file', field) self.assertFalse(field.url in output) self.assertTrue('href="something?chapter=1&sect=2&copy=3&lang=en"' in output) self.assertFalse(six.text_type(field) in output) self.assertTrue('something<div onclick="alert('oops')">.jpg' in output) self.assertTrue('my<div>file' in output) self.assertFalse('my
file' in output) def test_clear_input_renders_only_if_not_required(self): """ A ClearableFileInput with is_required=False does not render a clear checkbox. """ widget = ClearableFileInput() widget.is_required = True self.assertHTMLEqual(widget.render('myfile', FakeFieldFile()), 'Currently: something
Change: ') def test_clear_input_renders_only_if_initial(self): """ A ClearableFileInput instantiated with no initial value does not render a clear checkbox. """ widget = ClearableFileInput() widget.is_required = False self.assertHTMLEqual(widget.render('myfile', None), '') def test_clear_input_checked_returns_false(self): """ ClearableFileInput.value_from_datadict returns False if the clear checkbox is checked, if not required. """ widget = ClearableFileInput() widget.is_required = False self.assertEqual(widget.value_from_datadict( data={'myfile-clear': True}, files={}, name='myfile'), False) def test_clear_input_checked_returns_false_only_if_not_required(self): """ ClearableFileInput.value_from_datadict never returns False if the field is required. """ widget = ClearableFileInput() widget.is_required = True f = SimpleUploadedFile('something.txt', b'content') self.assertEqual(widget.value_from_datadict( data={'myfile-clear': True}, files={'myfile': f}, name='myfile'), f)