Skip to content
Browse files

[1.2.X] Migrated forms (minus localflavor) doctests. A huge thanks to…

… Daniel Lindsley for the patch.

Backport of r14570 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14575 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent 3cbcce4 commit 587c66f7a0020bedccda7368b93eb025c84d6ac0 @freakboy3742 freakboy3742 committed Nov 16, 2010
View
2 AUTHORS
@@ -305,7 +305,7 @@ answer newbie questions, and generally made Django that much better:
limodou
Philip Lindborg <philip.lindborg@gmail.com>
Simon Litchfield <simon@quo.com.au>
- Daniel Lindsley <polarcowz@gmail.com>
+ Daniel Lindsley <daniel@toastdriven.com>
Trey Long <trey@ktrl.com>
Laurent Luce <http://www.laurentluce.com>
Martin Mahner <http://www.mahner.org/>
View
399 tests/regressiontests/forms/error_messages.py
@@ -1,399 +0,0 @@
-# -*- coding: utf-8 -*-
-tests = r"""
->>> from django.forms import *
->>> from django.core.files.uploadedfile import SimpleUploadedFile
-
-# CharField ###################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['min_length'] = 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s'
->>> e['max_length'] = 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s'
->>> f = CharField(min_length=5, max_length=10, error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('1234')
-Traceback (most recent call last):
-...
-ValidationError: [u'LENGTH 4, MIN LENGTH 5']
->>> f.clean('12345678901')
-Traceback (most recent call last):
-...
-ValidationError: [u'LENGTH 11, MAX LENGTH 10']
-
-# IntegerField ################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
->>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
->>> f = IntegerField(min_value=5, max_value=10, error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
->>> f.clean('4')
-Traceback (most recent call last):
-...
-ValidationError: [u'MIN VALUE IS 5']
->>> f.clean('11')
-Traceback (most recent call last):
-...
-ValidationError: [u'MAX VALUE IS 10']
-
-# FloatField ##################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
->>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
->>> f = FloatField(min_value=5, max_value=10, error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
->>> f.clean('4')
-Traceback (most recent call last):
-...
-ValidationError: [u'MIN VALUE IS 5']
->>> f.clean('11')
-Traceback (most recent call last):
-...
-ValidationError: [u'MAX VALUE IS 10']
-
-# DecimalField ################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> e['min_value'] = 'MIN VALUE IS %(limit_value)s'
->>> e['max_value'] = 'MAX VALUE IS %(limit_value)s'
->>> e['max_digits'] = 'MAX DIGITS IS %s'
->>> e['max_decimal_places'] = 'MAX DP IS %s'
->>> e['max_whole_digits'] = 'MAX DIGITS BEFORE DP IS %s'
->>> f = DecimalField(min_value=5, max_value=10, error_messages=e)
->>> f2 = DecimalField(max_digits=4, decimal_places=2, error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
->>> f.clean('4')
-Traceback (most recent call last):
-...
-ValidationError: [u'MIN VALUE IS 5']
->>> f.clean('11')
-Traceback (most recent call last):
-...
-ValidationError: [u'MAX VALUE IS 10']
->>> f2.clean('123.45')
-Traceback (most recent call last):
-...
-ValidationError: [u'MAX DIGITS IS 4']
->>> f2.clean('1.234')
-Traceback (most recent call last):
-...
-ValidationError: [u'MAX DP IS 2']
->>> f2.clean('123.4')
-Traceback (most recent call last):
-...
-ValidationError: [u'MAX DIGITS BEFORE DP IS 2']
-
-# DateField ###################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> f = DateField(error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
-
-# TimeField ###################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> f = TimeField(error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
-
-# DateTimeField ###############################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> f = DateTimeField(error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
-
-# RegexField ##################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> e['min_length'] = 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s'
->>> e['max_length'] = 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s'
->>> f = RegexField(r'^\d+$', min_length=5, max_length=10, error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abcde')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
->>> f.clean('1234')
-Traceback (most recent call last):
-...
-ValidationError: [u'LENGTH 4, MIN LENGTH 5']
->>> f.clean('12345678901')
-Traceback (most recent call last):
-...
-ValidationError: [u'LENGTH 11, MAX LENGTH 10']
-
-# EmailField ##################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> e['min_length'] = 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s'
->>> e['max_length'] = 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s'
->>> f = EmailField(min_length=8, max_length=10, error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abcdefgh')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
->>> f.clean('a@b.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'LENGTH 7, MIN LENGTH 8']
->>> f.clean('aye@bee.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'LENGTH 11, MAX LENGTH 10']
-
-# FileField ##################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> e['missing'] = 'MISSING'
->>> e['empty'] = 'EMPTY FILE'
->>> f = FileField(error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
->>> f.clean(SimpleUploadedFile('name', None))
-Traceback (most recent call last):
-...
-ValidationError: [u'EMPTY FILE']
->>> f.clean(SimpleUploadedFile('name', ''))
-Traceback (most recent call last):
-...
-ValidationError: [u'EMPTY FILE']
-
-# URLField ##################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID'
->>> e['invalid_link'] = 'INVALID LINK'
->>> f = URLField(verify_exists=True, error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('abc.c')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID']
->>> f.clean('http://www.broken.djangoproject.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID LINK']
-
-# BooleanField ################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> f = BooleanField(error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
-
-# ChoiceField #################################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid_choice'] = '%(value)s IS INVALID CHOICE'
->>> f = ChoiceField(choices=[('a', 'aye')], error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('b')
-Traceback (most recent call last):
-...
-ValidationError: [u'b IS INVALID CHOICE']
-
-# MultipleChoiceField #########################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid_choice'] = '%(value)s IS INVALID CHOICE'
->>> e['invalid_list'] = 'NOT A LIST'
->>> f = MultipleChoiceField(choices=[('a', 'aye')], error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('b')
-Traceback (most recent call last):
-...
-ValidationError: [u'NOT A LIST']
->>> f.clean(['b'])
-Traceback (most recent call last):
-...
-ValidationError: [u'b IS INVALID CHOICE']
-
-# SplitDateTimeField ##########################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid_date'] = 'INVALID DATE'
->>> e['invalid_time'] = 'INVALID TIME'
->>> f = SplitDateTimeField(error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean(['a', 'b'])
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID DATE', u'INVALID TIME']
-
-# IPAddressField ##############################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid'] = 'INVALID IP ADDRESS'
->>> f = IPAddressField(error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('127.0.0')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID IP ADDRESS']
-
-###############################################################################
-
-# Create choices for the model choice field tests below.
-
->>> from regressiontests.forms.models import ChoiceModel
->>> ChoiceModel.objects.create(pk=1, name='a')
-<ChoiceModel: ChoiceModel object>
->>> ChoiceModel.objects.create(pk=2, name='b')
-<ChoiceModel: ChoiceModel object>
->>> ChoiceModel.objects.create(pk=3, name='c')
-<ChoiceModel: ChoiceModel object>
-
-# ModelChoiceField ############################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid_choice'] = 'INVALID CHOICE'
->>> f = ModelChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('4')
-Traceback (most recent call last):
-...
-ValidationError: [u'INVALID CHOICE']
-
-# ModelMultipleChoiceField ####################################################
-
->>> e = {'required': 'REQUIRED'}
->>> e['invalid_choice'] = '%s IS INVALID CHOICE'
->>> e['list'] = 'NOT A LIST OF VALUES'
->>> f = ModelMultipleChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'REQUIRED']
->>> f.clean('3')
-Traceback (most recent call last):
-...
-ValidationError: [u'NOT A LIST OF VALUES']
->>> f.clean(['4'])
-Traceback (most recent call last):
-...
-ValidationError: [u'4 IS INVALID CHOICE']
-
-# Subclassing ErrorList #######################################################
-
->>> from django.utils.safestring import mark_safe
->>>
->>> class TestForm(Form):
-... first_name = CharField()
-... last_name = CharField()
-... birthday = DateField()
-...
-... def clean(self):
-... raise ValidationError("I like to be awkward.")
-...
->>> class CustomErrorList(util.ErrorList):
-... def __unicode__(self):
-... return self.as_divs()
-... def as_divs(self):
-... if not self: return u''
-... return mark_safe(u'<div class="error">%s</div>'
-... % ''.join([u'<p>%s</p>' % e for e in self]))
-...
-
-This form should print errors the default way.
-
->>> form1 = TestForm({'first_name': 'John'})
->>> print form1['last_name'].errors
-<ul class="errorlist"><li>This field is required.</li></ul>
->>> print form1.errors['__all__']
-<ul class="errorlist"><li>I like to be awkward.</li></ul>
-
-This one should wrap error groups in the customized way.
-
->>> form2 = TestForm({'first_name': 'John'}, error_class=CustomErrorList)
->>> print form2['last_name'].errors
-<div class="error"><p>This field is required.</p></div>
->>> print form2.errors['__all__']
-<div class="error"><p>I like to be awkward.</p></div>
-
-"""
View
1,887 tests/regressiontests/forms/forms.py
0 additions, 1,887 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
724 tests/regressiontests/forms/formsets.py
@@ -1,724 +0,0 @@
-# -*- coding: utf-8 -*-
-tests = """
-# Basic FormSet creation and usage ############################################
-
-FormSet allows us to use multiple instance of the same form on 1 page. For now,
-the best way to create a FormSet is by using the formset_factory function.
-
->>> from django.forms import Form, CharField, IntegerField, ValidationError
->>> from django.forms.formsets import formset_factory, BaseFormSet
-
->>> class Choice(Form):
-... choice = CharField()
-... votes = IntegerField()
-
->>> ChoiceFormSet = formset_factory(Choice)
-
-A FormSet constructor takes the same arguments as Form. Let's create a FormSet
-for adding data. By default, it displays 1 blank form. It can display more,
-but we'll look at how to do so later.
-
->>> formset = ChoiceFormSet(auto_id=False, prefix='choices')
->>> print formset
-<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" />
-<tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr>
-<tr><th>Votes:</th><td><input type="text" name="choices-0-votes" /></td></tr>
-
-
-On thing to note is that there needs to be a special value in the data. This
-value tells the FormSet how many forms were displayed so it can tell how
-many forms it needs to clean and validate. You could use javascript to create
-new forms on the client side, but they won't get validated unless you increment
-the TOTAL_FORMS field appropriately.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '1', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... }
-
-We treat FormSet pretty much like we would treat a normal Form. FormSet has an
-is_valid method, and a cleaned_data or errors attribute depending on whether all
-the forms passed validation. However, unlike a Form instance, cleaned_data and
-errors will be a list of dicts rather than just a single dict.
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> [form.cleaned_data for form in formset.forms]
-[{'votes': 100, 'choice': u'Calexico'}]
-
-If a FormSet was not passed any data, its is_valid method should return False.
->>> formset = ChoiceFormSet()
->>> formset.is_valid()
-False
-
-FormSet instances can also have an error attribute if validation failed for
-any of the forms.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '1', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-False
->>> formset.errors
-[{'votes': [u'This field is required.']}]
-
-
-We can also prefill a FormSet with existing data by providing an ``initial``
-argument to the constructor. ``initial`` should be a list of dicts. By default,
-an extra blank form is included.
-
->>> initial = [{'choice': u'Calexico', 'votes': 100}]
->>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices')
->>> for form in formset.forms:
-... print form.as_ul()
-<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
-<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li>
-<li>Choice: <input type="text" name="choices-1-choice" /></li>
-<li>Votes: <input type="text" name="choices-1-votes" /></li>
-
-
-Let's simulate what would happen if we submitted this form.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '2', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '1', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... 'choices-1-choice': '',
-... 'choices-1-votes': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> [form.cleaned_data for form in formset.forms]
-[{'votes': 100, 'choice': u'Calexico'}, {}]
-
-But the second form was blank! Shouldn't we get some errors? No. If we display
-a form as blank, it's ok for it to be submitted as blank. If we fill out even
-one of the fields of a blank form though, it will be validated. We may want to
-required that at least x number of forms are completed, but we'll show how to
-handle that later.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '2', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '1', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... 'choices-1-choice': 'The Decemberists',
-... 'choices-1-votes': '', # missing value
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-False
->>> formset.errors
-[{}, {'votes': [u'This field is required.']}]
-
-If we delete data that was pre-filled, we should get an error. Simply removing
-data from form fields isn't the proper way to delete it. We'll see how to
-handle that case later.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '2', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '1', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': '', # deleted value
-... 'choices-0-votes': '', # deleted value
-... 'choices-1-choice': '',
-... 'choices-1-votes': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-False
->>> formset.errors
-[{'votes': [u'This field is required.'], 'choice': [u'This field is required.']}, {}]
-
-
-# Displaying more than 1 blank form ###########################################
-
-We can also display more than 1 empty form at a time. To do so, pass a
-extra argument to formset_factory.
-
->>> ChoiceFormSet = formset_factory(Choice, extra=3)
-
->>> formset = ChoiceFormSet(auto_id=False, prefix='choices')
->>> for form in formset.forms:
-... print form.as_ul()
-<li>Choice: <input type="text" name="choices-0-choice" /></li>
-<li>Votes: <input type="text" name="choices-0-votes" /></li>
-<li>Choice: <input type="text" name="choices-1-choice" /></li>
-<li>Votes: <input type="text" name="choices-1-votes" /></li>
-<li>Choice: <input type="text" name="choices-2-choice" /></li>
-<li>Votes: <input type="text" name="choices-2-votes" /></li>
-
-Since we displayed every form as blank, we will also accept them back as blank.
-This may seem a little strange, but later we will show how to require a minimum
-number of forms to be completed.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '3', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': '',
-... 'choices-0-votes': '',
-... 'choices-1-choice': '',
-... 'choices-1-votes': '',
-... 'choices-2-choice': '',
-... 'choices-2-votes': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> [form.cleaned_data for form in formset.forms]
-[{}, {}, {}]
-
-
-We can just fill out one of the forms.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '3', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... 'choices-1-choice': '',
-... 'choices-1-votes': '',
-... 'choices-2-choice': '',
-... 'choices-2-votes': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> [form.cleaned_data for form in formset.forms]
-[{'votes': 100, 'choice': u'Calexico'}, {}, {}]
-
-
-And once again, if we try to partially complete a form, validation will fail.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '3', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... 'choices-1-choice': 'The Decemberists',
-... 'choices-1-votes': '', # missing value
-... 'choices-2-choice': '',
-... 'choices-2-votes': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-False
->>> formset.errors
-[{}, {'votes': [u'This field is required.']}, {}]
-
-
-The extra argument also works when the formset is pre-filled with initial
-data.
-
->>> initial = [{'choice': u'Calexico', 'votes': 100}]
->>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices')
->>> for form in formset.forms:
-... print form.as_ul()
-<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
-<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li>
-<li>Choice: <input type="text" name="choices-1-choice" /></li>
-<li>Votes: <input type="text" name="choices-1-votes" /></li>
-<li>Choice: <input type="text" name="choices-2-choice" /></li>
-<li>Votes: <input type="text" name="choices-2-votes" /></li>
-<li>Choice: <input type="text" name="choices-3-choice" /></li>
-<li>Votes: <input type="text" name="choices-3-votes" /></li>
-
-Make sure retrieving an empty form works, and it shows up in the form list
-
->>> formset.empty_form.empty_permitted
-True
->>> print formset.empty_form.as_ul()
-<li>Choice: <input type="text" name="choices-__prefix__-choice" /></li>
-<li>Votes: <input type="text" name="choices-__prefix__-votes" /></li>
-
-# FormSets with deletion ######################################################
-
-We can easily add deletion ability to a FormSet with an argument to
-formset_factory. This will add a boolean field to each form instance. When
-that boolean field is True, the form will be in formset.deleted_forms
-
->>> ChoiceFormSet = formset_factory(Choice, can_delete=True)
-
->>> initial = [{'choice': u'Calexico', 'votes': 100}, {'choice': u'Fergie', 'votes': 900}]
->>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices')
->>> for form in formset.forms:
-... print form.as_ul()
-<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
-<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li>
-<li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li>
-<li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li>
-<li>Votes: <input type="text" name="choices-1-votes" value="900" /></li>
-<li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li>
-<li>Choice: <input type="text" name="choices-2-choice" /></li>
-<li>Votes: <input type="text" name="choices-2-votes" /></li>
-<li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li>
-
-To delete something, we just need to set that form's special delete field to
-'on'. Let's go ahead and delete Fergie.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '3', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '2', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... 'choices-0-DELETE': '',
-... 'choices-1-choice': 'Fergie',
-... 'choices-1-votes': '900',
-... 'choices-1-DELETE': 'on',
-... 'choices-2-choice': '',
-... 'choices-2-votes': '',
-... 'choices-2-DELETE': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> [form.cleaned_data for form in formset.forms]
-[{'votes': 100, 'DELETE': False, 'choice': u'Calexico'}, {'votes': 900, 'DELETE': True, 'choice': u'Fergie'}, {}]
->>> [form.cleaned_data for form in formset.deleted_forms]
-[{'votes': 900, 'DELETE': True, 'choice': u'Fergie'}]
-
-If we fill a form with something and then we check the can_delete checkbox for
-that form, that form's errors should not make the entire formset invalid since
-it's going to be deleted.
-
->>> class CheckForm(Form):
-... field = IntegerField(min_value=100)
-
->>> data = {
-... 'check-TOTAL_FORMS': '3', # the number of forms rendered
-... 'check-INITIAL_FORMS': '2', # the number of forms with initial data
-... 'check-MAX_NUM_FORMS': '0', # max number of forms
-... 'check-0-field': '200',
-... 'check-0-DELETE': '',
-... 'check-1-field': '50',
-... 'check-1-DELETE': 'on',
-... 'check-2-field': '',
-... 'check-2-DELETE': '',
-... }
->>> CheckFormSet = formset_factory(CheckForm, can_delete=True)
->>> formset = CheckFormSet(data, prefix='check')
->>> formset.is_valid()
-True
-
-If we remove the deletion flag now we will have our validation back.
-
->>> data['check-1-DELETE'] = ''
->>> formset = CheckFormSet(data, prefix='check')
->>> formset.is_valid()
-False
-
-Should be able to get deleted_forms from a valid formset even if a
-deleted form would have been invalid.
-
->>> class Person(Form):
-... name = CharField()
-
->>> PeopleForm = formset_factory(
-... form=Person,
-... can_delete=True)
-
->>> p = PeopleForm(
-... {'form-0-name': u'', 'form-0-DELETE': u'on', # no name!
-... 'form-TOTAL_FORMS': 1, 'form-INITIAL_FORMS': 1,
-... 'form-MAX_NUM_FORMS': 1})
-
->>> p.is_valid()
-True
->>> len(p.deleted_forms)
-1
-
-# FormSets with ordering ######################################################
-
-We can also add ordering ability to a FormSet with an agrument to
-formset_factory. This will add a integer field to each form instance. When
-form validation succeeds, [form.cleaned_data for form in formset.forms] will have the data in the correct
-order specified by the ordering fields. If a number is duplicated in the set
-of ordering fields, for instance form 0 and form 3 are both marked as 1, then
-the form index used as a secondary ordering criteria. In order to put
-something at the front of the list, you'd need to set it's order to 0.
-
->>> ChoiceFormSet = formset_factory(Choice, can_order=True)
-
->>> initial = [{'choice': u'Calexico', 'votes': 100}, {'choice': u'Fergie', 'votes': 900}]
->>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices')
->>> for form in formset.forms:
-... print form.as_ul()
-<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
-<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li>
-<li>Order: <input type="text" name="choices-0-ORDER" value="1" /></li>
-<li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li>
-<li>Votes: <input type="text" name="choices-1-votes" value="900" /></li>
-<li>Order: <input type="text" name="choices-1-ORDER" value="2" /></li>
-<li>Choice: <input type="text" name="choices-2-choice" /></li>
-<li>Votes: <input type="text" name="choices-2-votes" /></li>
-<li>Order: <input type="text" name="choices-2-ORDER" /></li>
-
->>> data = {
-... 'choices-TOTAL_FORMS': '3', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '2', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... 'choices-0-ORDER': '1',
-... 'choices-1-choice': 'Fergie',
-... 'choices-1-votes': '900',
-... 'choices-1-ORDER': '2',
-... 'choices-2-choice': 'The Decemberists',
-... 'choices-2-votes': '500',
-... 'choices-2-ORDER': '0',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> for form in formset.ordered_forms:
-... print form.cleaned_data
-{'votes': 500, 'ORDER': 0, 'choice': u'The Decemberists'}
-{'votes': 100, 'ORDER': 1, 'choice': u'Calexico'}
-{'votes': 900, 'ORDER': 2, 'choice': u'Fergie'}
-
-Ordering fields are allowed to be left blank, and if they *are* left blank,
-they will be sorted below everything else.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '4', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '3', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... 'choices-0-ORDER': '1',
-... 'choices-1-choice': 'Fergie',
-... 'choices-1-votes': '900',
-... 'choices-1-ORDER': '2',
-... 'choices-2-choice': 'The Decemberists',
-... 'choices-2-votes': '500',
-... 'choices-2-ORDER': '',
-... 'choices-3-choice': 'Basia Bulat',
-... 'choices-3-votes': '50',
-... 'choices-3-ORDER': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> for form in formset.ordered_forms:
-... print form.cleaned_data
-{'votes': 100, 'ORDER': 1, 'choice': u'Calexico'}
-{'votes': 900, 'ORDER': 2, 'choice': u'Fergie'}
-{'votes': 500, 'ORDER': None, 'choice': u'The Decemberists'}
-{'votes': 50, 'ORDER': None, 'choice': u'Basia Bulat'}
-
-Ordering should work with blank fieldsets.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '3', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> for form in formset.ordered_forms:
-... print form.cleaned_data
-
-# FormSets with ordering + deletion ###########################################
-
-Let's try throwing ordering and deletion into the same form.
-
->>> ChoiceFormSet = formset_factory(Choice, can_order=True, can_delete=True)
-
->>> initial = [
-... {'choice': u'Calexico', 'votes': 100},
-... {'choice': u'Fergie', 'votes': 900},
-... {'choice': u'The Decemberists', 'votes': 500},
-... ]
->>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices')
->>> for form in formset.forms:
-... print form.as_ul()
-<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
-<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li>
-<li>Order: <input type="text" name="choices-0-ORDER" value="1" /></li>
-<li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li>
-<li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li>
-<li>Votes: <input type="text" name="choices-1-votes" value="900" /></li>
-<li>Order: <input type="text" name="choices-1-ORDER" value="2" /></li>
-<li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li>
-<li>Choice: <input type="text" name="choices-2-choice" value="The Decemberists" /></li>
-<li>Votes: <input type="text" name="choices-2-votes" value="500" /></li>
-<li>Order: <input type="text" name="choices-2-ORDER" value="3" /></li>
-<li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li>
-<li>Choice: <input type="text" name="choices-3-choice" /></li>
-<li>Votes: <input type="text" name="choices-3-votes" /></li>
-<li>Order: <input type="text" name="choices-3-ORDER" /></li>
-<li>Delete: <input type="checkbox" name="choices-3-DELETE" /></li>
-
-Let's delete Fergie, and put The Decemberists ahead of Calexico.
-
->>> data = {
-... 'choices-TOTAL_FORMS': '4', # the number of forms rendered
-... 'choices-INITIAL_FORMS': '3', # the number of forms with initial data
-... 'choices-MAX_NUM_FORMS': '0', # max number of forms
-... 'choices-0-choice': 'Calexico',
-... 'choices-0-votes': '100',
-... 'choices-0-ORDER': '1',
-... 'choices-0-DELETE': '',
-... 'choices-1-choice': 'Fergie',
-... 'choices-1-votes': '900',
-... 'choices-1-ORDER': '2',
-... 'choices-1-DELETE': 'on',
-... 'choices-2-choice': 'The Decemberists',
-... 'choices-2-votes': '500',
-... 'choices-2-ORDER': '0',
-... 'choices-2-DELETE': '',
-... 'choices-3-choice': '',
-... 'choices-3-votes': '',
-... 'choices-3-ORDER': '',
-... 'choices-3-DELETE': '',
-... }
-
->>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
->>> formset.is_valid()
-True
->>> for form in formset.ordered_forms:
-... print form.cleaned_data
-{'votes': 500, 'DELETE': False, 'ORDER': 0, 'choice': u'The Decemberists'}
-{'votes': 100, 'DELETE': False, 'ORDER': 1, 'choice': u'Calexico'}
->>> [form.cleaned_data for form in formset.deleted_forms]
-[{'votes': 900, 'DELETE': True, 'ORDER': 2, 'choice': u'Fergie'}]
-
-Should be able to get ordered forms from a valid formset even if a
-deleted form would have been invalid.
-
->>> class Person(Form):
-... name = CharField()
-
->>> PeopleForm = formset_factory(
-... form=Person,
-... can_delete=True,
-... can_order=True)
-
->>> p = PeopleForm(
-... {'form-0-name': u'', 'form-0-DELETE': u'on', # no name!
-... 'form-TOTAL_FORMS': 1, 'form-INITIAL_FORMS': 1,
-... 'form-MAX_NUM_FORMS': 1})
-
->>> p.is_valid()
-True
->>> p.ordered_forms
-[]
-
-# FormSet clean hook ##########################################################
-
-FormSets have a hook for doing extra validation that shouldn't be tied to any
-particular form. It follows the same pattern as the clean hook on Forms.
-
-Let's define a FormSet that takes a list of favorite drinks, but raises am
-error if there are any duplicates.
-
->>> class FavoriteDrinkForm(Form):
-... name = CharField()
-...
-
->>> class BaseFavoriteDrinksFormSet(BaseFormSet):
-... def clean(self):
-... seen_drinks = []
-... for drink in self.cleaned_data:
-... if drink['name'] in seen_drinks:
-... raise ValidationError('You may only specify a drink once.')
-... seen_drinks.append(drink['name'])
-...
-
->>> FavoriteDrinksFormSet = formset_factory(FavoriteDrinkForm,
-... formset=BaseFavoriteDrinksFormSet, extra=3)
-
-We start out with a some duplicate data.
-
->>> data = {
-... 'drinks-TOTAL_FORMS': '2', # the number of forms rendered
-... 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'drinks-MAX_NUM_FORMS': '0', # max number of forms
-... 'drinks-0-name': 'Gin and Tonic',
-... 'drinks-1-name': 'Gin and Tonic',
-... }
-
->>> formset = FavoriteDrinksFormSet(data, prefix='drinks')
->>> formset.is_valid()
-False
-
-Any errors raised by formset.clean() are available via the
-formset.non_form_errors() method.
-
->>> for error in formset.non_form_errors():
-... print error
-You may only specify a drink once.
-
-
-Make sure we didn't break the valid case.
-
->>> data = {
-... 'drinks-TOTAL_FORMS': '2', # the number of forms rendered
-... 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'drinks-MAX_NUM_FORMS': '0', # max number of forms
-... 'drinks-0-name': 'Gin and Tonic',
-... 'drinks-1-name': 'Bloody Mary',
-... }
-
->>> formset = FavoriteDrinksFormSet(data, prefix='drinks')
->>> formset.is_valid()
-True
->>> for error in formset.non_form_errors():
-... print error
-
-# Limiting the maximum number of forms ########################################
-
-# Base case for max_num.
-
-# When not passed, max_num will take its default value of None, i.e. unlimited
-# number of forms, only controlled by the value of the extra parameter.
-
->>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3)
->>> formset = LimitedFavoriteDrinkFormSet()
->>> for form in formset.forms:
-... print form
-<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>
-<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>
-<tr><th><label for="id_form-2-name">Name:</label></th><td><input type="text" name="form-2-name" id="id_form-2-name" /></td></tr>
-
-# If max_num is 0 then no form is rendered at all.
-
->>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=0)
->>> formset = LimitedFavoriteDrinkFormSet()
->>> for form in formset.forms:
-... print form
-
->>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=5, max_num=2)
->>> formset = LimitedFavoriteDrinkFormSet()
->>> for form in formset.forms:
-... print form
-<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>
-<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>
-
-# Ensure that max_num has no effect when extra is less than max_num.
-
->>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=2)
->>> formset = LimitedFavoriteDrinkFormSet()
->>> for form in formset.forms:
-... print form
-<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>
-
-# max_num with initial data
-
-# When not passed, max_num will take its default value of None, i.e. unlimited
-# number of forms, only controlled by the values of the initial and extra
-# parameters.
-
->>> initial = [
-... {'name': 'Fernet and Coke'},
-... ]
->>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1)
->>> formset = LimitedFavoriteDrinkFormSet(initial=initial)
->>> for form in formset.forms:
-... print form
-<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" value="Fernet and Coke" id="id_form-0-name" /></td></tr>
-<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>
-
-# If max_num is 0 then no form is rendered at all, even if extra and initial
-# are specified.
-
->>> initial = [
-... {'name': 'Fernet and Coke'},
-... {'name': 'Bloody Mary'},
-... ]
->>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=0)
->>> formset = LimitedFavoriteDrinkFormSet(initial=initial)
->>> for form in formset.forms:
-... print form
-
-# More initial forms than max_num will result in only the first max_num of
-# them to be displayed with no extra forms.
-
->>> initial = [
-... {'name': 'Gin Tonic'},
-... {'name': 'Bloody Mary'},
-... {'name': 'Jack and Coke'},
-... ]
->>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=2)
->>> formset = LimitedFavoriteDrinkFormSet(initial=initial)
->>> for form in formset.forms:
-... print form
-<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name" /></td></tr>
-<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" value="Bloody Mary" id="id_form-1-name" /></td></tr>
-
-# One form from initial and extra=3 with max_num=2 should result in the one
-# initial form and one extra.
-
->>> initial = [
-... {'name': 'Gin Tonic'},
-... ]
->>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=2)
->>> formset = LimitedFavoriteDrinkFormSet(initial=initial)
->>> for form in formset.forms:
-... print form
-<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name" /></td></tr>
-<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>
-
-
-# Regression test for #6926 ##################################################
-
-Make sure the management form has the correct prefix.
-
->>> formset = FavoriteDrinksFormSet()
->>> formset.management_form.prefix
-'form'
-
->>> formset = FavoriteDrinksFormSet(data={})
->>> formset.management_form.prefix
-'form'
-
->>> formset = FavoriteDrinksFormSet(initial={})
->>> formset.management_form.prefix
-'form'
-
-# Regression test for #12878 #################################################
-
->>> data = {
-... 'drinks-TOTAL_FORMS': '2', # the number of forms rendered
-... 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data
-... 'drinks-MAX_NUM_FORMS': '0', # max number of forms
-... 'drinks-0-name': 'Gin and Tonic',
-... 'drinks-1-name': 'Gin and Tonic',
-... }
-
->>> formset = FavoriteDrinksFormSet(data, prefix='drinks')
->>> formset.is_valid()
-False
->>> print formset.non_form_errors()
-<ul class="errorlist"><li>You may only specify a drink once.</li></ul>
-
-"""
View
21 tests/regressiontests/forms/tests.py → ...regressiontests/forms/localflavortests.py
@@ -1,7 +1,4 @@
# -*- coding: utf-8 -*-
-from extra import tests as extra_tests
-from forms import tests as form_tests
-from error_messages import tests as custom_error_message_tests
from localflavor.ar import tests as localflavor_ar_tests
from localflavor.at import tests as localflavor_at_tests
from localflavor.au import tests as localflavor_au_tests
@@ -31,22 +28,9 @@
from localflavor.us import tests as localflavor_us_tests
from localflavor.uy import tests as localflavor_uy_tests
from localflavor.za import tests as localflavor_za_tests
-from regressions import tests as regression_tests
-from util import tests as util_tests
-from widgets import tests as widgets_tests
-from formsets import tests as formset_tests
-from media import media_tests
-from fields import FieldsTests
-from validators import TestFieldWithValidators
-from widgets import WidgetTests
-
-from input_formats import *
__test__ = {
- 'extra_tests': extra_tests,
- 'form_tests': form_tests,
- 'custom_error_message_tests': custom_error_message_tests,
'localflavor_ar_tests': localflavor_ar_tests,
'localflavor_at_tests': localflavor_at_tests,
'localflavor_au_tests': localflavor_au_tests,
@@ -76,11 +60,6 @@
'localflavor_us_tests': localflavor_us_tests,
'localflavor_uy_tests': localflavor_uy_tests,
'localflavor_za_tests': localflavor_za_tests,
- 'regression_tests': regression_tests,
- 'formset_tests': formset_tests,
- 'media_tests': media_tests,
- 'util_tests': util_tests,
- 'widgets_tests': widgets_tests,
}
if __name__ == "__main__":
View
385 tests/regressiontests/forms/media.py
@@ -1,385 +0,0 @@
-# -*- coding: utf-8 -*-
-# Tests for the media handling on widgets and forms
-
-media_tests = r"""
->>> from django.forms import TextInput, Media, TextInput, CharField, Form, MultiWidget
->>> from django.conf import settings
->>> ORIGINAL_MEDIA_URL = settings.MEDIA_URL
->>> settings.MEDIA_URL = 'http://media.example.com/media/'
-
-# Check construction of media objects
->>> m = Media(css={'all': ('path/to/css1','/path/to/css2')}, js=('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3'))
->>> print m
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-
->>> class Foo:
-... css = {
-... 'all': ('path/to/css1','/path/to/css2')
-... }
-... js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
->>> m3 = Media(Foo)
->>> print m3
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-
->>> m3 = Media(Foo)
->>> print m3
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-
-# A widget can exist without a media definition
->>> class MyWidget(TextInput):
-... pass
-
->>> w = MyWidget()
->>> print w.media
-<BLANKLINE>
-
-###############################################################
-# DSL Class-based media definitions
-###############################################################
-
-# A widget can define media if it needs to.
-# Any absolute path will be preserved; relative paths are combined
-# with the value of settings.MEDIA_URL
->>> class MyWidget1(TextInput):
-... class Media:
-... css = {
-... 'all': ('path/to/css1','/path/to/css2')
-... }
-... js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
-
->>> w1 = MyWidget1()
->>> print w1.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-
-# Media objects can be interrogated by media type
->>> print w1.media['css']
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-
->>> print w1.media['js']
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-
-# Media objects can be combined. Any given media resource will appear only
-# once. Duplicated media definitions are ignored.
->>> class MyWidget2(TextInput):
-... class Media:
-... css = {
-... 'all': ('/path/to/css2','/path/to/css3')
-... }
-... js = ('/path/to/js1','/path/to/js4')
-
->>> class MyWidget3(TextInput):
-... class Media:
-... css = {
-... 'all': ('/path/to/css3','path/to/css1')
-... }
-... js = ('/path/to/js1','/path/to/js4')
-
->>> w2 = MyWidget2()
->>> w3 = MyWidget3()
->>> print w1.media + w2.media + w3.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-# Check that media addition hasn't affected the original objects
->>> print w1.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-
-# Regression check for #12879: specifying the same CSS or JS file
-# multiple times in a single Media instance should result in that file
-# only being included once.
->>> class MyWidget4(TextInput):
-... class Media:
-... css = {'all': ('/path/to/css1', '/path/to/css1')}
-... js = ('/path/to/js1', '/path/to/js1')
-
->>> w4 = MyWidget4()
->>> print w4.media
-<link href="/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-
-
-###############################################################
-# Property-based media definitions
-###############################################################
-
-# Widget media can be defined as a property
->>> class MyWidget4(TextInput):
-... def _media(self):
-... return Media(css={'all': ('/some/path',)}, js = ('/some/js',))
-... media = property(_media)
-
->>> w4 = MyWidget4()
->>> print w4.media
-<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/some/js"></script>
-
-# Media properties can reference the media of their parents
->>> class MyWidget5(MyWidget4):
-... def _media(self):
-... return super(MyWidget5, self).media + Media(css={'all': ('/other/path',)}, js = ('/other/js',))
-... media = property(_media)
-
->>> w5 = MyWidget5()
->>> print w5.media
-<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
-<link href="/other/path" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/some/js"></script>
-<script type="text/javascript" src="/other/js"></script>
-
-# Media properties can reference the media of their parents,
-# even if the parent media was defined using a class
->>> class MyWidget6(MyWidget1):
-... def _media(self):
-... return super(MyWidget6, self).media + Media(css={'all': ('/other/path',)}, js = ('/other/js',))
-... media = property(_media)
-
->>> w6 = MyWidget6()
->>> print w6.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/other/path" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/other/js"></script>
-
-###############################################################
-# Inheritance of media
-###############################################################
-
-# If a widget extends another but provides no media definition, it inherits the parent widget's media
->>> class MyWidget7(MyWidget1):
-... pass
-
->>> w7 = MyWidget7()
->>> print w7.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-
-# If a widget extends another but defines media, it extends the parent widget's media by default
->>> class MyWidget8(MyWidget1):
-... class Media:
-... css = {
-... 'all': ('/path/to/css3','path/to/css1')
-... }
-... js = ('/path/to/js1','/path/to/js4')
-
->>> w8 = MyWidget8()
->>> print w8.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-# If a widget extends another but defines media, it extends the parents widget's media,
-# even if the parent defined media using a property.
->>> class MyWidget9(MyWidget4):
-... class Media:
-... css = {
-... 'all': ('/other/path',)
-... }
-... js = ('/other/js',)
-
->>> w9 = MyWidget9()
->>> print w9.media
-<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
-<link href="/other/path" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/some/js"></script>
-<script type="text/javascript" src="/other/js"></script>
-
-# A widget can disable media inheritance by specifying 'extend=False'
->>> class MyWidget10(MyWidget1):
-... class Media:
-... extend = False
-... css = {
-... 'all': ('/path/to/css3','path/to/css1')
-... }
-... js = ('/path/to/js1','/path/to/js4')
-
->>> w10 = MyWidget10()
->>> print w10.media
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-# A widget can explicitly enable full media inheritance by specifying 'extend=True'
->>> class MyWidget11(MyWidget1):
-... class Media:
-... extend = True
-... css = {
-... 'all': ('/path/to/css3','path/to/css1')
-... }
-... js = ('/path/to/js1','/path/to/js4')
-
->>> w11 = MyWidget11()
->>> print w11.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-# A widget can enable inheritance of one media type by specifying extend as a tuple
->>> class MyWidget12(MyWidget1):
-... class Media:
-... extend = ('css',)
-... css = {
-... 'all': ('/path/to/css3','path/to/css1')
-... }
-... js = ('/path/to/js1','/path/to/js4')
-
->>> w12 = MyWidget12()
->>> print w12.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-###############################################################
-# Multi-media handling for CSS
-###############################################################
-
-# A widget can define CSS media for multiple output media types
->>> class MultimediaWidget(TextInput):
-... class Media:
-... css = {
-... 'screen, print': ('/file1','/file2'),
-... 'screen': ('/file3',),
-... 'print': ('/file4',)
-... }
-... js = ('/path/to/js1','/path/to/js4')
-
->>> multimedia = MultimediaWidget()
->>> print multimedia.media
-<link href="/file4" type="text/css" media="print" rel="stylesheet" />
-<link href="/file3" type="text/css" media="screen" rel="stylesheet" />
-<link href="/file1" type="text/css" media="screen, print" rel="stylesheet" />
-<link href="/file2" type="text/css" media="screen, print" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-###############################################################
-# Multiwidget media handling
-###############################################################
-
-# MultiWidgets have a default media definition that gets all the
-# media from the component widgets
->>> class MyMultiWidget(MultiWidget):
-... def __init__(self, attrs=None):
-... widgets = [MyWidget1, MyWidget2, MyWidget3]
-... super(MyMultiWidget, self).__init__(widgets, attrs)
-
->>> mymulti = MyMultiWidget()
->>> print mymulti.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-###############################################################
-# Media processing for forms
-###############################################################
-
-# You can ask a form for the media required by its widgets.
->>> class MyForm(Form):
-... field1 = CharField(max_length=20, widget=MyWidget1())
-... field2 = CharField(max_length=20, widget=MyWidget2())
->>> f1 = MyForm()
->>> print f1.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-# Form media can be combined to produce a single media definition.
->>> class AnotherForm(Form):
-... field3 = CharField(max_length=20, widget=MyWidget3())
->>> f2 = AnotherForm()
->>> print f1.media + f2.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-
-# Forms can also define media, following the same rules as widgets.
->>> class FormWithMedia(Form):
-... field1 = CharField(max_length=20, widget=MyWidget1())
-... field2 = CharField(max_length=20, widget=MyWidget2())
-... class Media:
-... js = ('/some/form/javascript',)
-... css = {
-... 'all': ('/some/form/css',)
-... }
->>> f3 = FormWithMedia()
->>> print f3.media
-<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />
-<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-<script type="text/javascript" src="/some/form/javascript"></script>
-
-# Media works in templates
->>> from django.template import Template, Context
->>> Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3}))
-u'<script type="text/javascript" src="/path/to/js1"></script>
-<script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
-<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
-<script type="text/javascript" src="/path/to/js4"></script>
-<script type="text/javascript" src="/some/form/javascript"></script><link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
-<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
-<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />'
-
->>> settings.MEDIA_URL = ORIGINAL_MEDIA_URL
-"""
View
185 tests/regressiontests/forms/models.py
@@ -1,15 +1,9 @@
# -*- coding: utf-8 -*-
import datetime
import tempfile
-import shutil
-from django.db import models, connection
-from django.conf import settings
-# Can't import as "forms" due to implementation details in the test suite (the
-# current file is called "forms" and is already imported).
-from django import forms as django_forms
+from django.db import models
from django.core.files.storage import FileSystemStorage
-from django.test import TestCase
temp_storage_location = tempfile.mkdtemp()
temp_storage = FileSystemStorage(location=temp_storage_location)
@@ -57,188 +51,11 @@ class ChoiceFieldModel(models.Model):
multi_choice_int = models.ManyToManyField(ChoiceOptionModel, blank=False, related_name='multi_choice_int',
default=lambda: [1])
-class ChoiceFieldForm(django_forms.ModelForm):
- class Meta:
- model = ChoiceFieldModel
-
class FileModel(models.Model):
file = models.FileField(storage=temp_storage, upload_to='tests')
-class FileForm(django_forms.Form):
- file1 = django_forms.FileField()
-
class Group(models.Model):
name = models.CharField(max_length=10)
def __unicode__(self):
return u'%s' % self.name
-
-class TestTicket12510(TestCase):
- ''' It is not necessary to generate choices for ModelChoiceField (regression test for #12510). '''
- def setUp(self):
- self.groups = [Group.objects.create(name=name) for name in 'abc']
- self.old_debug = settings.DEBUG
- # turn debug on to get access to connection.queries
- settings.DEBUG = True
-
- def tearDown(self):
- settings.DEBUG = self.old_debug
-
- def test_choices_not_fetched_when_not_rendering(self):
- initial_queries = len(connection.queries)
- field = django_forms.ModelChoiceField(Group.objects.order_by('-name'))
- self.assertEqual('a', field.clean(self.groups[0].pk).name)
- # only one query is required to pull the model from DB
- self.assertEqual(initial_queries+1, len(connection.queries))
-
-class ModelFormCallableModelDefault(TestCase):
- def test_no_empty_option(self):
- "If a model's ForeignKey has blank=False and a default, no empty option is created (Refs #10792)."
- option = ChoiceOptionModel.objects.create(name='default')
-
- choices = list(ChoiceFieldForm().fields['choice'].choices)
- self.assertEquals(len(choices), 1)
- self.assertEquals(choices[0], (option.pk, unicode(option)))
-
- def test_callable_initial_value(self):
- "The initial value for a callable default returning a queryset is the pk (refs #13769)"
- obj1 = ChoiceOptionModel.objects.create(id=1, name='default')
- obj2 = ChoiceOptionModel.objects.create(id=2, name='option 2')
- obj3 = ChoiceOptionModel.objects.create(id=3, name='option 3')
- self.assertEquals(ChoiceFieldForm().as_p(), """<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice">
-<option value="1" selected="selected">ChoiceOption 1</option>
-<option value="2">ChoiceOption 2</option>
-<option value="3">ChoiceOption 3</option>
-</select><input type="hidden" name="initial-choice" value="1" id="initial-id_choice" /></p>
-<p><label for="id_choice_int">Choice int:</label> <select name="choice_int" id="id_choice_int">
-<option value="1" selected="selected">ChoiceOption 1</option>
-<option value="2">ChoiceOption 2</option>
-<option value="3">ChoiceOption 3</option>
-</select><input type="hidden" name="initial-choice_int" value="1" id="initial-id_choice_int" /></p>
-<p><label for="id_multi_choice">Multi choice:</label> <select multiple="multiple" name="multi_choice" id="id_multi_choice">
-<option value="1" selected="selected">ChoiceOption 1</option>
-<option value="2">ChoiceOption 2</option>
-<option value="3">ChoiceOption 3</option>
-</select><input type="hidden" name="initial-multi_choice" value="1" id="initial-id_multi_choice_0" /> Hold down "Control", or "Command" on a Mac, to select more than one.</p>
-<p><label for="id_multi_choice_int">Multi choice int:</label> <select multiple="multiple" name="multi_choice_int" id="id_multi_choice_int">
-<option value="1" selected="selected">ChoiceOption 1</option>
-<option value="2">ChoiceOption 2</option>
-<option value="3">ChoiceOption 3</option>
-</select><input type="hidden" name="initial-multi_choice_int" value="1" id="initial-id_multi_choice_int_0" /> Hold down "Control", or "Command" on a Mac, to select more than one.</p>""")
-
- def test_initial_instance_value(self):
- "Initial instances for model fields may also be instances (refs #7287)"
- obj1 = ChoiceOptionModel.objects.create(id=1, name='default')
- obj2 = ChoiceOptionModel.objects.create(id=2, name='option 2')
- obj3 = ChoiceOptionModel.objects.create(id=3, name='option 3')
- self.assertEquals(ChoiceFieldForm(initial={
- 'choice': obj2,
- 'choice_int': obj2,
- 'multi_choice': [obj2,obj3],
- 'multi_choice_int': ChoiceOptionModel.objects.exclude(name="default"),
- }).as_p(), """<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice">
-<option value="1">ChoiceOption 1</option>
-<option value="2" selected="selected">ChoiceOption 2</option>
-<option value="3">ChoiceOption 3</option>
-</select><input type="hidden" name="initial-choice" value="2" id="initial-id_choice" /></p>
-<p><label for="id_choice_int">Choice int:</label> <select name="choice_int" id="id_choice_int">
-<option value="1">ChoiceOption 1</option>
-<option value="2" selected="selected">ChoiceOption 2</option>
-<option value="3">ChoiceOption 3</option>
-</select><input type="hidden" name="initial-choice_int" value="2" id="initial-id_choice_int" /></p>
-<p><label for="id_multi_choice">Multi choice:</label> <select multiple="multiple" name="multi_choice" id="id_multi_choice">
-<option value="1">ChoiceOption 1</option>
-<option value="2" selected="selected">ChoiceOption 2</option>
-<option value="3" selected="selected">ChoiceOption 3</option>
-</select><input type="hidden" name="initial-multi_choice" value="2" id="initial-id_multi_choice_0" />
-<input type="hidden" name="initial-multi_choice" value="3" id="initial-id_multi_choice_1" /> Hold down "Control", or "Command" on a Mac, to select more than one.</p>
-<p><label for="id_multi_choice_int">Multi choice int:</label> <select multiple="multiple" name="multi_choice_int" id="id_multi_choice_int">
-<option value="1">ChoiceOption 1</option>
-<option value="2" selected="selected">ChoiceOption 2</option>
-<option value="3" selected="selected">ChoiceOption 3</option>
-</select><input type="hidden" name="initial-multi_choice_int" value="2" id="initial-id_multi_choice_int_0" />
-<input type="hidden" name="initial-multi_choice_int" value="3" id="initial-id_multi_choice_int_1" /> Hold down "Control", or "Command" on a Mac, to select more than one.</p>""")
-
-
-__test__ = {'API_TESTS': """
->>> from django.forms.models import ModelForm
->>> from django.core.files.uploadedfile import SimpleUploadedFile
-
-# FileModel with unicode filename and data #########################
->>> f = FileForm(data={}, files={'file1': SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह')}, auto_id=False)
->>> f.is_valid()
-True
->>> f.cleaned_data
-{'file1': <SimpleUploadedFile: 我隻氣墊船裝滿晒鱔.txt (text/plain)>}
->>> m = FileModel.objects.create(file=f.cleaned_data['file1'])
-
-# It's enough that m gets created without error. Preservation of the exotic name is checked
-# in a file_uploads test; it's hard to do that correctly with doctest's unicode issues. So
-# we create and then immediately delete m so as to not leave the exotically named file around
-# for shutil.rmtree (on Windows) to have trouble with later.
->>> m.delete()
-
-# Boundary conditions on a PostitiveIntegerField #########################
->>> class BoundaryForm(ModelForm):
-... class Meta:
-... model = BoundaryModel
->>> f = BoundaryForm({'positive_integer': 100})
->>> f.is_valid()
-True
->>> f = BoundaryForm({'positive_integer': 0})
->>> f.is_valid()
-True
->>> f = BoundaryForm({'positive_integer': -100})
->>> f.is_valid()
-False
-
-# Formfield initial values ########
-If the model has default values for some fields, they are used as the formfield
-initial values.
->>> class DefaultsForm(ModelForm):
-... class Meta:
-... model = Defaults
->>> DefaultsForm().fields['name'].initial
-u'class default value'
->>> DefaultsForm().fields['def_date'].initial
-datetime.date(1980, 1, 1)
->>> DefaultsForm().fields['value'].initial
-42
->>> r1 = DefaultsForm()['callable_default'].as_widget()
->>> r2 = DefaultsForm()['callable_default'].as_widget()
->>> r1 == r2
-False
-
-In a ModelForm that is passed an instance, the initial values come from the
-instance's values, not the model's defaults.
->>> foo_instance = Defaults(name=u'instance value', def_date=datetime.date(1969, 4, 4), value=12)
->>> instance_form = DefaultsForm(instance=foo_instance)
->>> instance_form.initial['name']
-u'instance value'
->>> instance_form.initial['def_date']
-datetime.date(1969, 4, 4)
->>> instance_form.initial['value']
-12
-
->>> from django.forms import CharField
->>> class ExcludingForm(ModelForm):
-... name = CharField(max_length=255)
-... class Meta:
-... model = Defaults
-... exclude = ['name', 'callable_default']
->>> f = ExcludingForm({'name': u'Hello', 'value': 99, 'def_date': datetime.date(1999, 3, 2)})
->>> f.is_valid()
-True
->>> f.cleaned_data['name']
-u'Hello'
->>> obj = f.save()
->>> obj.name
-u'class default value'
->>> obj.value
-99
->>> obj.def_date
-datetime.date(1999, 3, 2)
->>> shutil.rmtree(temp_storage_location)
-
-
-"""}
View
135 tests/regressiontests/forms/regressions.py
@@ -1,135 +0,0 @@
-# -*- coding: utf-8 -*-
-# Tests to prevent against recurrences of earlier bugs.
-
-tests = r"""
-It should be possible to re-use attribute dictionaries (#3810)
->>> from django.forms import *
->>> extra_attrs = {'class': 'special'}
->>> class TestForm(Form):
-... f1 = CharField(max_length=10, widget=TextInput(attrs=extra_attrs))
-... f2 = CharField(widget=TextInput(attrs=extra_attrs))
->>> TestForm(auto_id=False).as_p()
-u'<p>F1: <input type="text" class="special" name="f1" maxlength="10" /></p>\n<p>F2: <input type="text" class="special" name="f2" /></p>'
-
-#######################
-# Tests for form i18n #
-#######################
-There were some problems with form translations in #3600
-
->>> from django.utils.translation import ugettext_lazy, activate, deactivate
->>> class SomeForm(Form):
-... username = CharField(max_length=10, label=ugettext_lazy('Username'))
->>> f = SomeForm()
->>> print f.as_p()
-<p><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>
-
-Translations are done at rendering time, so multi-lingual apps can define forms
-early and still send back the right translation.
-
->>> activate('de')
->>> print f.as_p()
-<p><label for="id_username">Benutzername:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>
->>> activate('pl')
->>> f.as_p()
-u'<p><label for="id_username">Nazwa u\u017cytkownika:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>'
->>> deactivate()
-
-There was some problems with form translations in #5216
->>> class SomeForm(Form):
-... field_1 = CharField(max_length=10, label=ugettext_lazy('field_1'))
-... field_2 = CharField(max_length=10, label=ugettext_lazy('field_2'), widget=TextInput(attrs={'id': 'field_2_id'}))
->>> f = SomeForm()
->>> print f['field_1'].label_tag()
-<label for="id_field_1">field_1</label>
->>> print f['field_2'].label_tag()
-<label for="field_2_id">field_2</label>
-
-Unicode decoding problems...
->>> GENDERS = ((u'\xc5', u'En tied\xe4'), (u'\xf8', u'Mies'), (u'\xdf', u'Nainen'))
->>> class SomeForm(Form):
-... somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label=u'\xc5\xf8\xdf')
->>> f = SomeForm()
->>> f.as_p()
-u'<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>'
-
-Testing choice validation with UTF-8 bytestrings as input (these are the
-Russian abbreviations "мес." and "шт.".
-
->>> UNITS = (('\xd0\xbc\xd0\xb5\xd1\x81.', '\xd0\xbc\xd0\xb5\xd1\x81.'), ('\xd1\x88\xd1\x82.', '\xd1\x88\xd1\x82.'))
->>> f = ChoiceField(choices=UNITS)
->>> f.clean(u'\u0448\u0442.')
-u'\u0448\u0442.'
->>> f.clean('\xd1\x88\xd1\x82.')
-u'\u0448\u0442.'
-
-Translated error messages used to be buggy.
->>> activate('ru')
->>> f = SomeForm({})
->>> f.as_p()
-u'<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>'
->>> deactivate()
-
-Deep copying translated text shouldn't raise an error
->>> from django.utils.translation import gettext_lazy
->>> class CopyForm(Form):
-... degree = IntegerField(widget=Select(choices=((1, gettext_lazy('test')),)))
->>> f = CopyForm()
-
-#######################
-# Miscellaneous Tests #
-#######################
-
-There once was a problem with Form fields called "data". Let's make sure that
-doesn't come back.
->>> class DataForm(Form):
-... data = CharField(max_length=10)
->>> f = DataForm({'data': 'xyzzy'})
->>> f.is_valid()
-True
->>> f.cleaned_data
-{'data': u'xyzzy'}
-
-A form with *only* hidden fields that has errors is going to be very unusual.
-But we can try to make sure it doesn't generate invalid XHTML. In this case,
-the as_p() method is the tricky one, since error lists cannot be nested
-(validly) inside p elements.
-
->>> class HiddenForm(Form):
-... data = IntegerField(widget=HiddenInput)
->>> f = HiddenForm({})
->>> f.as_p()
-u'<ul class="errorlist"><li>(Hidden field data) This field is required.</li></ul>\n<p> <input type="hidden" name="data" id="id_data" /></p>'
->>> f.as_table()
-u'<tr><td colspan="2"><ul class="errorlist"><li>(Hidden field data) This field is required.</li></ul><input type="hidden" name="data" id="id_data" /></td></tr>'
-
-###################################################
-# Tests for XSS vulnerabilities in error messages #
-###################################################
-
-# The forms layer doesn't escape input values directly because error messages
-# might be presented in non-HTML contexts. Instead, the message is just marked
-# for escaping by the template engine. So we'll need to construct a little
-# silly template to trigger the escaping.
-
->>> from django.template import Template, Context
->>> t = Template('{{ form.errors }}')
-
->>> class SomeForm(Form):
-... field = ChoiceField(choices=[('one', 'One')])
->>> f = SomeForm({'field': '<script>'})
->>> t.render(Context({'form': f}))
-u'<ul class="errorlist"><li>field<ul class="errorlist"><li>Select a valid choice. &lt;script&gt; is not one of the available choices.</li></ul></li></ul>'
-
->>> class SomeForm(Form):
-... field = MultipleChoiceField(choices=[('one', 'One')])
->>> f = SomeForm({'field': ['<script>']})
->>> t.render(Context({'form': f}))
-u'<ul class="errorlist"><li>field<ul class="errorlist"><li>Select a valid choice. &lt;script&gt; is not one of the available choices.</li></ul></li></ul>'
-
->>> from regressiontests.forms.models import ChoiceModel
->>> class SomeForm(Form):
-... field = ModelMultipleChoiceField(ChoiceModel.objects.all())
->>> f = SomeForm({'field': ['<script>']})
->>> t.render(Context({'form': f}))
-u'<ul class="errorlist"><li>field<ul class="errorlist"><li>&quot;&lt;script&gt;&quot; is not a valid value for a primary key.</li></ul></li></ul>'
-"""
View
14 tests/regressiontests/forms/tests/__init__.py
@@ -0,0 +1,14 @@
+from error_messages import *
+from extra import *
+from fields import FieldsTests
+from forms import *
+from formsets import *
+from input_formats import *
+from media import *
+from models import *
+from regressions import *
+from util import *
+from validators import TestFieldWithValidators
+from widgets import *
+
+from regressiontests.forms.localflavortests import __test__
View
253 tests/regressiontests/forms/tests/error_messages.py
@@ -0,0 +1,253 @@
+# -*- coding: utf-8 -*-
+import unittest
+from django.core.files.uploadedfile import SimpleUploadedFile
+from django.forms import *
+from django.test import TestCase
+from django.utils.safestring import mark_safe
+
+class AssertFormErrorsMixin(object):
+ def assertFormErrors(self, expected, the_callable, *args, **kwargs):
+ try:
+ the_callable(*args, **kwargs)
+ self.fail("Testing the 'clean' method on %s failed to raise a ValidationError.")
+ except ValidationError, e:
+ self.assertEqual(e.messages, expected)
+
+
+class FormsErrorMessagesTestCase(unittest.TestCase, AssertFormErrorsMixin):
+ def test_charfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'min_length': 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s',
+ 'max_length': 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s',
+ }
+ f = CharField(min_length=5, max_length=10, error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'LENGTH 4, MIN LENGTH 5'], f.clean, '1234')
+ self.assertFormErrors([u'LENGTH 11, MAX LENGTH 10'], f.clean, '12345678901')
+
+ def test_integerfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ 'min_value': 'MIN VALUE IS %(limit_value)s',
+ 'max_value': 'MAX VALUE IS %(limit_value)s',
+ }
+ f = IntegerField(min_value=5, max_value=10, error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abc')
+ self.assertFormErrors([u'MIN VALUE IS 5'], f.clean, '4')
+ self.assertFormErrors([u'MAX VALUE IS 10'], f.clean, '11')
+
+ def test_floatfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ 'min_value': 'MIN VALUE IS %(limit_value)s',
+ 'max_value': 'MAX VALUE IS %(limit_value)s',
+ }
+ f = FloatField(min_value=5, max_value=10, error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abc')
+ self.assertFormErrors([u'MIN VALUE IS 5'], f.clean, '4')
+ self.assertFormErrors([u'MAX VALUE IS 10'], f.clean, '11')
+
+ def test_decimalfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ 'min_value': 'MIN VALUE IS %(limit_value)s',
+ 'max_value': 'MAX VALUE IS %(limit_value)s',
+ 'max_digits': 'MAX DIGITS IS %s',
+ 'max_decimal_places': 'MAX DP IS %s',
+ 'max_whole_digits': 'MAX DIGITS BEFORE DP IS %s',
+ }
+ f = DecimalField(min_value=5, max_value=10, error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abc')
+ self.assertFormErrors([u'MIN VALUE IS 5'], f.clean, '4')
+ self.assertFormErrors([u'MAX VALUE IS 10'], f.clean, '11')
+
+ f2 = DecimalField(max_digits=4, decimal_places=2, error_messages=e)
+ self.assertFormErrors([u'MAX DIGITS IS 4'], f2.clean, '123.45')
+ self.assertFormErrors([u'MAX DP IS 2'], f2.clean, '1.234')
+ self.assertFormErrors([u'MAX DIGITS BEFORE DP IS 2'], f2.clean, '123.4')
+
+ def test_datefield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ }
+ f = DateField(error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abc')
+
+ def test_timefield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ }
+ f = TimeField(error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abc')
+
+ def test_datetimefield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ }
+ f = DateTimeField(error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abc')
+
+ def test_regexfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ 'min_length': 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s',
+ 'max_length': 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s',
+ }
+ f = RegexField(r'^\d+$', min_length=5, max_length=10, error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abcde')
+ self.assertFormErrors([u'LENGTH 4, MIN LENGTH 5'], f.clean, '1234')
+ self.assertFormErrors([u'LENGTH 11, MAX LENGTH 10'], f.clean, '12345678901')
+
+ def test_emailfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ 'min_length': 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s',
+ 'max_length': 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s',
+ }
+ f = EmailField(min_length=8, max_length=10, error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abcdefgh')
+ self.assertFormErrors([u'LENGTH 7, MIN LENGTH 8'], f.clean, 'a@b.com')
+ self.assertFormErrors([u'LENGTH 11, MAX LENGTH 10'], f.clean, 'aye@bee.com')
+
+ def test_filefield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ 'missing': 'MISSING',
+ 'empty': 'EMPTY FILE',
+ }
+ f = FileField(error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abc')
+ self.assertFormErrors([u'EMPTY FILE'], f.clean, SimpleUploadedFile('name', None))
+ self.assertFormErrors([u'EMPTY FILE'], f.clean, SimpleUploadedFile('name', ''))
+
+ def test_urlfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID',
+ 'invalid_link': 'INVALID LINK',
+ }
+ f = URLField(verify_exists=True, error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID'], f.clean, 'abc.c')
+ self.assertFormErrors([u'INVALID LINK'], f.clean, 'http://www.broken.djangoproject.com')
+
+ def test_booleanfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ }
+ f = BooleanField(error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+
+ def test_choicefield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid_choice': '%(value)s IS INVALID CHOICE',
+ }
+ f = ChoiceField(choices=[('a', 'aye')], error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'b IS INVALID CHOICE'], f.clean, 'b')
+
+ def test_multiplechoicefield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid_choice': '%(value)s IS INVALID CHOICE',
+ 'invalid_list': 'NOT A LIST',
+ }
+ f = MultipleChoiceField(choices=[('a', 'aye')], error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'NOT A LIST'], f.clean, 'b')
+ self.assertFormErrors([u'b IS INVALID CHOICE'], f.clean, ['b'])
+
+ def test_splitdatetimefield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid_date': 'INVALID DATE',
+ 'invalid_time': 'INVALID TIME',
+ }
+ f = SplitDateTimeField(error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID DATE', u'INVALID TIME'], f.clean, ['a', 'b'])
+
+ def test_ipaddressfield(self):
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid': 'INVALID IP ADDRESS',
+ }
+ f = IPAddressField(error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID IP ADDRESS'], f.clean, '127.0.0')
+
+ def test_subclassing_errorlist(self):
+ class TestForm(Form):
+ first_name = CharField()
+ last_name = CharField()
+ birthday = DateField()
+
+ def clean(self):
+ raise ValidationError("I like to be awkward.")
+
+ class CustomErrorList(util.ErrorList):
+ def __unicode__(self):
+ return self.as_divs()
+
+ def as_divs(self):
+ if not self: return u''
+ return mark_safe(u'<div class="error">%s</div>' % ''.join([u'<p>%s</p>' % e for e in self]))
+
+ # This form should print errors the default way.
+ form1 = TestForm({'first_name': 'John'})
+ self.assertEqual(str(form1['last_name'].errors), '<ul class="errorlist"><li>This field is required.</li></ul>')
+ self.assertEqual(str(form1.errors['__all__']), '<ul class="errorlist"><li>I like to be awkward.</li></ul>')
+
+ # This one should wrap error groups in the customized way.
+ form2 = TestForm({'first_name': 'John'}, error_class=CustomErrorList)
+ self.assertEqual(str(form2['last_name'].errors), '<div class="error"><p>This field is required.</p></div>')
+ self.assertEqual(str(form2.errors['__all__']), '<div class="error"><p>I like to be awkward.</p></div>')
+
+
+class ModelChoiceFieldErrorMessagesTestCase(TestCase, AssertFormErrorsMixin):
+ def test_modelchoicefield(self):
+ # Create choices for the model choice field tests below.
+ from regressiontests.forms.models import ChoiceModel
+ c1 = ChoiceModel.objects.create(pk=1, name='a')
+ c2 = ChoiceModel.objects.create(pk=2, name='b')
+ c3 = ChoiceModel.objects.create(pk=3, name='c')
+
+ # ModelChoiceField
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid_choice': 'INVALID CHOICE',
+ }
+ f = ModelChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'INVALID CHOICE'], f.clean, '4')
+
+ # ModelMultipleChoiceField
+ e = {
+ 'required': 'REQUIRED',
+ 'invalid_choice': '%s IS INVALID CHOICE',
+ 'list': 'NOT A LIST OF VALUES',
+ }
+ f = ModelMultipleChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e)
+ self.assertFormErrors([u'REQUIRED'], f.clean, '')
+ self.assertFormErrors([u'NOT A LIST OF VALUES'], f.clean, '3')
+ self.assertFormErrors([u'4 IS INVALID CHOICE'], f.clean, ['4'])
View
564 tests/regressiontests/forms/extra.py → tests/regressiontests/forms/tests/extra.py
@@ -1,25 +1,29 @@
# -*- coding: utf-8 -*-
-tests = r"""
->>> from django.forms import *
->>> from django.utils.encoding import force_unicode
->>> import datetime
->>> import time
->>> import re
->>> from decimal import Decimal
-
-###############
-# Extra stuff #
-###############
-
-The forms library comes with some extra, higher-level Field and Widget
-classes that demonstrate some of the library's abilities.
-
-# SelectDateWidget ############################################################
-
->>> from django.forms.extras import SelectDateWidget
->>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'))
->>> print w.render('mydate', '')
-<select name="mydate_month" id="id_mydate_month">
+import datetime
+from decimal import Decimal
+import re
+import time
+import unittest
+from django.conf import settings
+from django.forms import *
+from django.forms.extras import SelectDateWidget
+from django.forms.util import ErrorList
+from django.test import TestCase
+from django.utils import translation
+from django.utils.encoding import force_unicode
+from django.utils.encoding import smart_unicode
+from error_messages import AssertFormErrorsMixin
+
+
+class FormsExtraTestCase(unittest.TestCase, AssertFormErrorsMixin):
+ ###############
+ # Extra stuff #
+ ###############
+
+ # The forms library comes with some extra, higher-level Field and Widget
+ def test_selectdate(self):
+ w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'))
+ self.assertEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month">
<option value="0">---</option>
<option value="1">January</option>
<option value="2">February</option>
@@ -80,11 +84,10 @@
<option value="2014">2014</option>
<option value="2015">2015</option>
<option value="2016">2016</option>
-</select>
->>> w.render('mydate', None) == w.render('mydate', '')
-True
->>> print w.render('mydate', '2010-04-15')
-<select name="mydate_month" id="id_mydate_month">
+</select>""")
+ self.assertEqual(w.render('mydate', None), w.render('mydate', ''))
+
+ self.assertEqual(w.render('mydate', '2010-04-15'), """<select name="mydate_month" id="id_mydate_month">
<option value="1">January</option>
<option value="2">February</option>
<option value="3">March</option>
@@ -142,16 +145,13 @@
<option value="2014">2014</option>
<option value="2015">2015</option>
<option value="2016">2016</option>
-</select>
-
-Accepts a datetime or a string:
+</select>""")
->>> w.render('mydate', datetime.date(2010, 4, 15)) == w.render('mydate', '2010-04-15')
-True
+ # Accepts a datetime or a string:
+ self.assertEqual(w.render('mydate', datetime.date(2010, 4, 15)), w.render('mydate', '2010-04-15'))
-Invalid dates still render the failed date:
->>> print w.render('mydate', '2010-02-31')
-<select name="mydate_month" id="id_mydate_month">
+ # Invalid dates still render the failed date:
+ self.assertEqual(w.render('mydate', '2010-02-31'), """<select name="mydate_month" id="id_mydate_month">