Django

Code

Show
Ignore:
Timestamp:
12/10/06 09:43:51 (2 years ago)
Author:
jpellerin
Message:

[multi-db] Merged trunk to [4188]. Some tests still failing.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/multiple-db-support/tests/regressiontests/forms/tests.py

    r4159 r4189  
    637637              Widget that it'll use if you don't specify this. In most cases, 
    638638              the default widget is TextInput. 
     639    label -- A verbose name for this field, for use in displaying this field in 
     640             a form. By default, Django will use a "pretty" version of the form 
     641             field name, if the Field is part of a Form. 
    639642 
    640643Other than that, the Field subclasses have class-specific options for 
     
    13361339<input type="text" name="birthday" value="1940-10-9" /> 
    13371340>>> for boundfield in p: 
    1338 ...     print boundfield.verbose_name, boundfield.data 
     1341...     print boundfield.label, boundfield.data 
    13391342First name John 
    13401343Last name Lennon 
     
    13691372<li><ul class="errorlist"><li>This field is required.</li></ul>Last name: <input type="text" name="last_name" /></li> 
    13701373<li><ul class="errorlist"><li>This field is required.</li></ul>Birthday: <input type="text" name="birthday" /></li> 
     1374>>> print p.as_p() 
     1375<p><ul class="errorlist"><li>This field is required.</li></ul></p> 
     1376<p>First name: <input type="text" name="first_name" /></p> 
     1377<p><ul class="errorlist"><li>This field is required.</li></ul></p> 
     1378<p>Last name: <input type="text" name="last_name" /></p> 
     1379<p><ul class="errorlist"><li>This field is required.</li></ul></p> 
     1380<p>Birthday: <input type="text" name="birthday" /></p> 
    13711381 
    13721382If you don't pass any values to the Form's __init__(), or if you pass None, 
     
    13901400<li>Last name: <input type="text" name="last_name" /></li> 
    13911401<li>Birthday: <input type="text" name="birthday" /></li> 
     1402>>> print p.as_p() 
     1403<p>First name: <input type="text" name="first_name" /></p> 
     1404<p>Last name: <input type="text" name="last_name" /></p> 
     1405<p>Birthday: <input type="text" name="birthday" /></p> 
    13921406 
    13931407Unicode values are handled properly. 
     
    13971411>>> p.as_ul() 
    13981412u'<li>First name: <input type="text" name="first_name" value="John" /></li>\n<li>Last name: <input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /></li>\n<li>Birthday: <input type="text" name="birthday" value="1940-10-9" /></li>' 
     1413>>> p.as_p() 
     1414u'<p>First name: <input type="text" name="first_name" value="John" /></p>\n<p>Last name: <input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /></p>\n<p>Birthday: <input type="text" name="birthday" value="1940-10-9" /></p>' 
    13991415 
    14001416>>> p = Person({'last_name': u'Lennon'}) 
     
    14331449the human-readable labels for a field. 
    14341450>>> p = Person(auto_id='id_%s') 
     1451>>> print p.as_table() 
     1452<tr><td><label for="id_first_name">First name:</label></td><td><input type="text" name="first_name" id="id_first_name" /></td></tr> 
     1453<tr><td><label for="id_last_name">Last name:</label></td><td><input type="text" name="last_name" id="id_last_name" /></td></tr> 
     1454<tr><td><label for="id_birthday">Birthday:</label></td><td><input type="text" name="birthday" id="id_birthday" /></td></tr> 
    14351455>>> print p.as_ul() 
    14361456<li><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li> 
    14371457<li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li> 
    14381458<li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li> 
    1439 >>> print p.as_table() 
    1440 <tr><td><label for="id_first_name">First name:</label></td><td><input type="text" name="first_name" id="id_first_name" /></td></tr
    1441 <tr><td><label for="id_last_name">Last name:</label></td><td><input type="text" name="last_name" id="id_last_name" /></td></tr
    1442 <tr><td><label for="id_birthday">Birthday:</label></td><td><input type="text" name="birthday" id="id_birthday" /></td></tr
     1459>>> print p.as_p() 
     1460<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></p
     1461<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></p
     1462<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></p
    14431463 
    14441464If auto_id is any True value whose str() does not contain '%s', the "id" 
     
    15971617<li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 
    15981618</ul></li> 
     1619>>> print f.as_p() 
     1620<p><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p> 
     1621<p><label for="id_language_0">Language:</label> <ul> 
     1622<li><label><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> 
     1623<li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 
     1624</ul></p> 
    15991625 
    16001626MultipleChoiceField is a special case, as its data is required to be a list: 
     
    17141740>>> print f.as_table() 
    17151741<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 
    1716 <tr><td>Username:</td><td><input type="text" name="username" /></td></tr> 
     1742<tr><td>Username:</td><td><input type="text" name="username" maxlength="10" /></td></tr> 
    17171743<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 
    17181744<tr><td>Password1:</td><td><input type="password" name="password1" /></td></tr> 
     
    17261752>>> print f.as_table() 
    17271753<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr> 
    1728 <tr><td>Username:</td><td><input type="text" name="username" value="adrian" /></td></tr> 
     1754<tr><td>Username:</td><td><input type="text" name="username" value="adrian" maxlength="10" /></td></tr> 
    17291755<tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr> 
    17301756<tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr> 
    17311757>>> print f.as_ul() 
    17321758<li><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></li> 
    1733 <li>Username: <input type="text" name="username" value="adrian" /></li> 
     1759<li>Username: <input type="text" name="username" value="adrian" maxlength="10" /></li> 
    17341760<li>Password1: <input type="password" name="password1" value="foo" /></li> 
    17351761<li>Password2: <input type="password" name="password2" value="bar" /></li> 
     
    17551781<tr><td>Birthday:</td><td><input type="text" name="birthday" /></td></tr> 
    17561782 
    1757 HiddenInput widgets are displayed differently in the as_table() and as_ul() 
    1758 output of a Form -- their verbose names are not displayed, and a separate 
    1759 <tr>/<li> is not displayed. 
     1783HiddenInput widgets are displayed differently in the as_table(), as_ul() 
     1784and as_p() output of a Form -- their verbose names are not displayed, and a 
     1785separate row is not displayed. They're displayed in the last row of the 
     1786form, directly after that row's form element. 
    17601787>>> class Person(Form): 
    17611788...     first_name = CharField() 
     
    17671794<tr><td>First name:</td><td><input type="text" name="first_name" /></td></tr> 
    17681795<tr><td>Last name:</td><td><input type="text" name="last_name" /></td></tr> 
    1769 <input type="hidden" name="hidden_text" /> 
    1770 <tr><td>Birthday:</td><td><input type="text" name="birthday" /></td></tr> 
     1796<tr><td>Birthday:</td><td><input type="text" name="birthday" /><input type="hidden" name="hidden_text" /></td></tr> 
    17711797>>> print p.as_ul() 
    17721798<li>First name: <input type="text" name="first_name" /></li> 
    17731799<li>Last name: <input type="text" name="last_name" /></li> 
    1774 <input type="hidden" name="hidden_text" /> 
    1775 <li>Birthday: <input type="text" name="birthday" /></li> 
     1800<li>Birthday: <input type="text" name="birthday" /><input type="hidden" name="hidden_text" /></li> 
     1801>>> print p.as_p() 
     1802<p>First name: <input type="text" name="first_name" /></p> 
     1803<p>Last name: <input type="text" name="last_name" /></p> 
     1804<p>Birthday: <input type="text" name="birthday" /><input type="hidden" name="hidden_text" /></p> 
    17761805 
    17771806With auto_id set, a HiddenInput still gets an ID, but it doesn't get a label. 
     
    17801809<tr><td><label for="id_first_name">First name:</label></td><td><input type="text" name="first_name" id="id_first_name" /></td></tr> 
    17811810<tr><td><label for="id_last_name">Last name:</label></td><td><input type="text" name="last_name" id="id_last_name" /></td></tr> 
    1782 <input type="hidden" name="hidden_text" id="id_hidden_text" /> 
    1783 <tr><td><label for="id_birthday">Birthday:</label></td><td><input type="text" name="birthday" id="id_birthday" /></td></tr> 
     1811<tr><td><label for="id_birthday">Birthday:</label></td><td><input type="text" name="birthday" id="id_birthday" /><input type="hidden" name="hidden_text" id="id_hidden_text" /></td></tr> 
    17841812>>> print p.as_ul() 
    17851813<li><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li> 
    17861814<li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li> 
    1787 <input type="hidden" name="hidden_text" id="id_hidden_text" /> 
    1788 <li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li> 
     1815<li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /><input type="hidden" name="hidden_text" id="id_hidden_text" /></li> 
     1816>>> print p.as_p() 
     1817<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></p> 
     1818<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></p> 
     1819<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /><input type="hidden" name="hidden_text" id="id_hidden_text" /></p> 
    17891820 
    17901821If a field with a HiddenInput has errors, the as_table() and as_ul() output 
    17911822will include the error message(s) with the text "(Hidden field [fieldname]) " 
    1792 prepended. 
     1823prepended. This message is displayed at the top of the output, regardless of 
     1824its field's order in the form. 
    17931825>>> p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'}) 
    17941826>>> print p 
     1827<tr><td colspan="2"><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></td></tr> 
    17951828<tr><td>First name:</td><td><input type="text" name="first_name" value="John" /></td></tr> 
    17961829<tr><td>Last name:</td><td><input type="text" name="last_name" value="Lennon" /></td></tr> 
    1797 <tr><td colspan="2"><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></td></tr> 
    1798 <input type="hidden" name="hidden_text" /> 
    1799 <tr><td>Birthday:</td><td><input type="text" name="birthday" value="1940-10-9" /></td></tr> 
     1830<tr><td>Birthday:</td><td><input type="text" name="birthday" value="1940-10-9" /><input type="hidden" name="hidden_text" /></td></tr> 
    18001831>>> print p.as_ul() 
     1832<li><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></li> 
    18011833<li>First name: <input type="text" name="first_name" value="John" /></li> 
    18021834<li>Last name: <input type="text" name="last_name" value="Lennon" /></li> 
    1803 <li><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></li> 
    1804 <input type="hidden" name="hidden_text" /> 
    1805 <li>Birthday: <input type="text" name="birthday" value="1940-10-9" /></li> 
     1835<li>Birthday: <input type="text" name="birthday" value="1940-10-9" /><input type="hidden" name="hidden_text" /></li> 
     1836>>> print p.as_p() 
     1837<p><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></p> 
     1838<p>First name: <input type="text" name="first_name" value="John" /></p> 
     1839<p>Last name: <input type="text" name="last_name" value="Lennon" /></p> 
     1840<p>Birthday: <input type="text" name="birthday" value="1940-10-9" /><input type="hidden" name="hidden_text" /></p> 
     1841 
     1842A corner case: It's possible for a form to have only HiddenInputs. 
     1843>>> class TestForm(Form): 
     1844...     foo = CharField(widget=HiddenInput) 
     1845...     bar = CharField(widget=HiddenInput) 
     1846>>> p = TestForm() 
     1847>>> print p.as_table() 
     1848<input type="hidden" name="foo" /><input type="hidden" name="bar" /> 
     1849>>> print p.as_ul() 
     1850<input type="hidden" name="foo" /><input type="hidden" name="bar" /> 
     1851>>> print p.as_p() 
     1852<input type="hidden" name="foo" /><input type="hidden" name="bar" /> 
    18061853 
    18071854A Form's fields are displayed in the same order in which they were defined. 
     
    18381885<tr><td>Field14:</td><td><input type="text" name="field14" /></td></tr> 
    18391886 
     1887Some Field classes have an effect on the HTML attributes of their associated 
     1888Widget. If you set max_length in a CharField and its associated widget is 
     1889either a TextInput or PasswordInput, then the widget's rendered HTML will 
     1890include the "maxlength" attribute. 
     1891>>> class UserRegistration(Form): 
     1892...    username = CharField(max_length=10)                   # uses TextInput by default 
     1893...    password = CharField(max_length=10, widget=PasswordInput) 
     1894...    realname = CharField(max_length=10, widget=TextInput) # redundantly define widget, just to test 
     1895...    address = CharField()                                 # no max_length defined here 
     1896>>> p = UserRegistration() 
     1897>>> print p.as_ul() 
     1898<li>Username: <input type="text" name="username" maxlength="10" /></li> 
     1899<li>Password: <input type="password" name="password" maxlength="10" /></li> 
     1900<li>Realname: <input type="text" name="realname" maxlength="10" /></li> 
     1901<li>Address: <input type="text" name="address" /></li> 
     1902 
     1903If you specify a custom "attrs" that includes the "maxlength" attribute, 
     1904the Field's max_length attribute will override whatever "maxlength" you specify 
     1905in "attrs". 
     1906>>> class UserRegistration(Form): 
     1907...    username = CharField(max_length=10, widget=TextInput(attrs={'maxlength': 20})) 
     1908...    password = CharField(max_length=10, widget=PasswordInput) 
     1909>>> p = UserRegistration() 
     1910>>> print p.as_ul() 
     1911<li>Username: <input type="text" name="username" maxlength="10" /></li> 
     1912<li>Password: <input type="password" name="password" maxlength="10" /></li> 
     1913 
     1914You can specify the label for a field by using the 'label' argument to a Field 
     1915class. If you don't specify 'label', Django will use the field name with 
     1916underscores converted to spaces, and the initial letter capitalized. 
     1917>>> class UserRegistration(Form): 
     1918...    username = CharField(max_length=10, label='Your username') 
     1919...    password1 = CharField(widget=PasswordInput) 
     1920...    password2 = CharField(widget=PasswordInput, label='Password (again)') 
     1921>>> p = UserRegistration() 
     1922>>> print p.as_ul() 
     1923<li>Your username: <input type="text" name="username" maxlength="10" /></li> 
     1924<li>Password1: <input type="password" name="password1" /></li> 
     1925<li>Password (again): <input type="password" name="password2" /></li> 
     1926 
    18401927# Basic form processing in a view ############################################# 
    18411928 
     
    18631950<form action="" method="post"> 
    18641951<table> 
    1865 <tr><td>Username:</td><td><input type="text" name="username" /></td></tr> 
     1952<tr><td>Username:</td><td><input type="text" name="username" maxlength="10" /></td></tr> 
    18661953<tr><td>Password1:</td><td><input type="password" name="password1" /></td></tr> 
    18671954<tr><td>Password2:</td><td><input type="password" name="password2" /></td></tr> 
     
    18761963<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr> 
    18771964<tr><td colspan="2"><ul class="errorlist"><li>Ensure this value has at most 10 characters.</li></ul></td></tr> 
    1878 <tr><td>Username:</td><td><input type="text" name="username" value="this-is-a-long-username" /></td></tr> 
     1965<tr><td>Username:</td><td><input type="text" name="username" value="this-is-a-long-username" maxlength="10" /></td></tr> 
    18791966<tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr> 
    18801967<tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr> 
     
    19111998>>> print t.render(Context({'form': UserRegistration()})) 
    19121999<form action=""> 
    1913 <p><label>Your username: <input type="text" name="username" /></label></p> 
     2000<p><label>Your username: <input type="text" name="username" maxlength="10" /></label></p> 
    19142001<p><label>Password: <input type="password" name="password1" /></label></p> 
    19152002<p><label>Password (again): <input type="password" name="password2" /></label></p> 
     
    19182005>>> print t.render(Context({'form': UserRegistration({'username': 'django'})})) 
    19192006<form action=""> 
    1920 <p><label>Your username: <input type="text" name="username" value="django" /></label></p> 
     2007<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" /></label></p> 
    19212008<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password: <input type="password" name="password1" /></label></p> 
    19222009<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password (again): <input type="password" name="password2" /></label></p> 
     
    19242011</form> 
    19252012 
    1926 Use form.[field].verbose_name to output a field's "verbose name" -- its field 
    1927 name with underscores converted to spaces, and the initial letter capitalized. 
     2013Use form.[field].label to output a field's label. You can specify the label for 
     2014a field by using the 'label' argument to a Field class. If you don't specify 
     2015'label', Django will use the field name with underscores converted to spaces, 
     2016and the initial letter capitalized. 
    19282017>>> t = Template('''<form action=""> 
    1929 ... <p><label>{{ form.username.verbose_name }}: {{ form.username }}</label></p> 
    1930 ... <p><label>{{ form.password1.verbose_name }}: {{ form.password1 }}</label></p> 
    1931 ... <p><label>{{ form.password2.verbose_name }}: {{ form.password2 }}</label></p> 
     2018... <p><label>{{ form.username.label }}: {{ form.username }}</label></p> 
     2019... <p><label>{{ form.password1.label }}: {{ form.password1 }}</label></p> 
     2020... <p><label>{{ form.password2.label }}: {{ form.password2 }}</label></p> 
    19322021... <input type="submit" /> 
    19332022... </form>''') 
    19342023>>> print t.render(Context({'form': UserRegistration()})) 
    19352024<form action=""> 
    1936 <p><label>Username: <input type="text" name="username" /></label></p> 
     2025<p><label>Username: <input type="text" name="username" maxlength="10" /></label></p> 
    19372026<p><label>Password1: <input type="password" name="password1" /></label></p> 
    19382027<p><label>Password2: <input type="password" name="password2" /></label></p> 
     
    19402029</form> 
    19412030 
    1942 User form.[field].label_tag to output a field's verbose_name with a <label> 
    1943 tag wrapped around it, but *only* if the given field has an "id" attribute. 
     2031User form.[field].label_tag to output a field's label with a <label> tag 
     2032wrapped around it, but *only* if the given field has an "id" attribute. 
    19442033Recall from above that passing the "auto_id" argument to a Form gives each 
    19452034field an "id" attribute. 
     
    19522041>>> print t.render(Context({'form': UserRegistration()})) 
    19532042<form action=""> 
    1954 <p>Username: <input type="text" name="username" /></p> 
     2043<p>Username: <input type="text" name="username" maxlength="10" /></p> 
    19552044<p>Password1: <input type="password" name="password1" /></p> 
    19562045<p>Password2: <input type="password" name="password2" /></p> 
     
    19592048>>> print t.render(Context({'form': UserRegistration(auto_id='id_%s')})) 
    19602049<form action=""> 
    1961 <p><label for="id_username">Username</label>: <input type="text" name="username" id="id_username" /></p> 
     2050<p><label for="id_username">Username</label>: <input id="id_username" type="text" name="username" maxlength="10" /></p> 
    19622051<p><label for="id_password1">Password1</label>: <input type="password" name="password1" id="id_password1" /></p> 
    19632052<p><label for="id_password2">Password2</label>: <input type="password" name="password2" id="id_password2" /></p> 
     
    19772066>>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})})) 
    19782067<form action=""> 
    1979 <p><label>Your username: <input type="text" name="username" value="django" /></label></p> 
     2068<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" /></label></p> 
    19802069<p><label>Password: <input type="password" name="password1" value="foo" /></label></p> 
    19812070<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p> 
     
    19922081<form action=""> 
    19932082<ul class="errorlist"><li>Please make sure your passwords match.</li></ul> 
    1994 <p><label>Your username: <input type="text" name="username" value="django" /></label></p> 
     2083<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" /></label></p> 
    19952084<p><label>Password: <input type="password" name="password1" value="foo" /></label></p> 
    19962085<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p> 
  • django/branches/multiple-db-support/tests/regressiontests/templates/tests.py

    r4157 r4189  
     1# -*- coding: utf-8 -*- 
    12from django.conf import settings 
    23 
     
    6364        return "OtherClass.method" 
    6465 
     66class UnicodeInStrClass: 
     67    "Class whose __str__ returns a Unicode object." 
     68    def __str__(self): 
     69        return u'ŠĐĆŽćžšđ' 
     70 
    6571class Templates(unittest.TestCase): 
    6672    def test_templates(self): 
     
    173179            # Empty strings can be passed as arguments to filters 
    174180            'basic-syntax36': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'), 
     181 
     182            # If a variable has a __str__() that returns a Unicode object, the value 
     183            # will be converted to a bytestring. 
     184            'basic-syntax37': (r'{{ var }}', {'var': UnicodeInStrClass()}, '\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91'), 
    175185 
    176186            ### COMMENT SYNTAX ######################################################## 
     
    329339            'ifchanged06': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2)}, '1222'), 
    330340            'ifchanged07': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2), 'numy': (3, 3, 3)}, '1233323332333'), 
    331              
     341 
    332342            # Test one parameter given to ifchanged. 
    333343            'ifchanged-param01': ('{% for n in num %}{% ifchanged n %}..{% endifchanged %}{{ n }}{% endfor %}', { 'num': (1,2,3) }, '..1..2..3'), 
    334344            'ifchanged-param02': ('{% for n in num %}{% for x in numx %}{% ifchanged n %}..{% endifchanged %}{{ x }}{% endfor %}{% endfor %}', { 'num': (1,2,3), 'numx': (5,6,7) }, '..567..567..567'), 
    335              
     345 
    336346            # Test multiple parameters to ifchanged. 
    337347            'ifchanged-param03': ('{% for n in num %}{{ n }}{% for x in numx %}{% ifchanged x n %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1,1,2), 'numx': (5,6,6) }, '156156256'), 
    338              
     348 
    339349            # Test a date+hour like construct, where the hour of the last day 
    340350            # is the same but the date had changed, so print the hour anyway. 
    341351            'ifchanged-param04': ('{% for d in days %}{% ifchanged %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'), 
    342              
     352 
    343353            # Logically the same as above, just written with explicit 
    344354            # ifchanged for the day.