summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBoulder Sprinters <boulder-sprinters@djangoproject.com>2006-12-28 17:17:52 +0000
committerBoulder Sprinters <boulder-sprinters@djangoproject.com>2006-12-28 17:17:52 +0000
commit58ba520f32821140c96725b1f68ff31d64751844 (patch)
tree0d13c17580762dd9cdea2a9c52350d946545113b /tests
parentf4aa4933226a78d04cdbfda9119e64212a80e5b7 (diff)
boulder-oracle-sprint: Merged to trunk [4253]
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@4254 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
-rw-r--r--tests/modeltests/basic/models.py15
-rw-r--r--tests/modeltests/many_to_many/models.py12
-rw-r--r--tests/modeltests/model_forms/models.py166
-rw-r--r--tests/regressiontests/forms/tests.py391
4 files changed, 544 insertions, 40 deletions
diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py
index ebf870ee12..2ebe857e7e 100644
--- a/tests/modeltests/basic/models.py
+++ b/tests/modeltests/basic/models.py
@@ -12,6 +12,9 @@ class Article(models.Model):
class Meta:
ordering = ('pub_date',)
+ class Meta:
+ ordering = ('pub_date','headline')
+
def __str__(self):
return self.headline
@@ -247,7 +250,7 @@ datetime.datetime(2005, 7, 28, 0, 0)
# Slices (without step) are lazy:
>>> Article.objects.all()[0:5].filter()
-[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Fourth article>, <Article: Article 6>]
+[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Article 6>, <Article: Default headline>]
# Slicing again works:
>>> Article.objects.all()[0:5][0:2]
@@ -255,17 +258,17 @@ datetime.datetime(2005, 7, 28, 0, 0)
>>> Article.objects.all()[0:5][:2]
[<Article: Area woman programs in Python>, <Article: Second article>]
>>> Article.objects.all()[0:5][4:]
-[<Article: Article 6>]
+[<Article: Default headline>]
>>> Article.objects.all()[0:5][5:]
[]
# Some more tests!
>>> Article.objects.all()[2:][0:2]
-[<Article: Third article>, <Article: Fourth article>]
+[<Article: Third article>, <Article: Article 6>]
>>> Article.objects.all()[2:][:2]
-[<Article: Third article>, <Article: Fourth article>]
+[<Article: Third article>, <Article: Article 6>]
>>> Article.objects.all()[2:][2:3]
-[<Article: Article 6>]
+[<Article: Default headline>]
# Note that you can't use 'offset' without 'limit' (on some dbs), so this doesn't work:
>>> Article.objects.all()[2:]
@@ -314,7 +317,7 @@ AttributeError: Manager isn't accessible via Article instances
# Bulk delete test: How many objects before and after the delete?
>>> Article.objects.all()
-[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Fourth article>, <Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>]
+[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Article 6>, <Article: Default headline>, <Article: Fourth article>, <Article: Article 7>, <Article: Updated article 8>]
>>> Article.objects.filter(id__lte=4).delete()
>>> Article.objects.all()
[<Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>]
diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py
index 357f3ca629..38f8931ee7 100644
--- a/tests/modeltests/many_to_many/models.py
+++ b/tests/modeltests/many_to_many/models.py
@@ -231,4 +231,16 @@ __test__ = {'API_TESTS':"""
>>> p1.article_set.all()
[<Article: NASA uses Python>]
+# An alternate to calling clear() is to assign the empty set
+>>> p1.article_set = []
+>>> p1.article_set.all()
+[]
+
+>>> a2.publications = [p1, new_publication]
+>>> a2.publications.all()
+[<Publication: Highlights for Children>, <Publication: The Python Journal>]
+>>> a2.publications = []
+>>> a2.publications.all()
+[]
+
"""}
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index b51b4e1a8b..60a3defde5 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -2,13 +2,26 @@
34. Generating HTML forms from models
Django provides shortcuts for creating Form objects from a model class.
+
+The function django.newforms.form_for_model() takes a model class and returns
+a Form that is tied to the model. This Form works just like any other Form,
+with one additional method: create(). The create() method creates an instance
+of the model and returns that newly created instance. It saves the instance to
+the database if create(save=True), which is default. If you pass
+create(save=False), then you'll get the object without saving it.
"""
from django.db import models
class Category(models.Model):
name = models.CharField(maxlength=20)
- url = models.CharField('The URL', maxlength=20)
+ url = models.CharField('The URL', maxlength=40)
+
+ def __str__(self):
+ return self.name
+
+class Writer(models.Model):
+ name = models.CharField(maxlength=50)
def __str__(self):
return self.name
@@ -16,29 +29,156 @@ class Category(models.Model):
class Article(models.Model):
headline = models.CharField(maxlength=50)
pub_date = models.DateTimeField()
- categories = models.ManyToManyField(Category)
+ writer = models.ForeignKey(Writer)
+ categories = models.ManyToManyField(Category, blank=True)
def __str__(self):
return self.headline
__test__ = {'API_TESTS': """
->>> from django.newforms import form_for_model
+>>> from django.newforms import form_for_model, form_for_instance, BaseForm
+>>> import datetime
+
+>>> Category.objects.all()
+[]
+
>>> CategoryForm = form_for_model(Category)
>>> f = CategoryForm()
>>> print f
-<tr><th><label for="id_id">ID:</label></th><td><input type="text" name="id" id="id_id" /></td></tr>
-<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name" /></td></tr>
-<tr><th><label for="id_url">The URL:</label></th><td><input type="text" name="url" id="id_url" /></td></tr>
+<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
+<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>
>>> print f.as_ul()
-<li><label for="id_id">ID:</label> <input type="text" name="id" id="id_id" /></li>
-<li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></li>
-<li><label for="id_url">The URL:</label> <input type="text" name="url" id="id_url" /></li>
+<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" maxlength="20" /></li>
+<li><label for="id_url">The URL:</label> <input id="id_url" type="text" name="url" maxlength="40" /></li>
>>> print f['name']
-<input type="text" name="name" id="id_name" />
+<input id="id_name" type="text" name="name" maxlength="20" />
>>> f = CategoryForm(auto_id=False)
>>> print f.as_ul()
-<li>ID: <input type="text" name="id" /></li>
-<li>Name: <input type="text" name="name" /></li>
-<li>The URL: <input type="text" name="url" /></li>
+<li>Name: <input type="text" name="name" maxlength="20" /></li>
+<li>The URL: <input type="text" name="url" maxlength="40" /></li>
+
+>>> f = CategoryForm({'name': 'Entertainment', 'url': 'entertainment'})
+>>> f.errors
+{}
+>>> f.clean_data
+{'url': u'entertainment', 'name': u'Entertainment'}
+>>> obj = f.create()
+>>> obj
+<Category: Entertainment>
+>>> Category.objects.all()
+[<Category: Entertainment>]
+
+>>> f = CategoryForm({'name': "It's a test", 'url': 'test'})
+>>> f.errors
+{}
+>>> f.clean_data
+{'url': u'test', 'name': u"It's a test"}
+>>> obj = f.create()
+>>> obj
+<Category: It's a test>
+>>> Category.objects.all()
+[<Category: Entertainment>, <Category: It's a test>]
+
+>>> f = CategoryForm({'name': 'Third test', 'url': 'third'})
+>>> f.errors
+{}
+>>> f.clean_data
+{'url': u'third', 'name': u'Third test'}
+>>> obj = f.create(save=False)
+>>> obj
+<Category: Third test>
+>>> Category.objects.all()
+[<Category: Entertainment>, <Category: It's a test>]
+>>> obj.save()
+>>> Category.objects.all()
+[<Category: Entertainment>, <Category: It's a test>, <Category: Third test>]
+
+>>> f = CategoryForm({'name': '', 'url': 'foo'})
+>>> f.errors
+{'name': [u'This field is required.']}
+>>> f.clean_data
+>>> f.create()
+Traceback (most recent call last):
+...
+ValueError: The Category could not be created because the data didn't validate.
+
+>>> f = CategoryForm({'name': '', 'url': 'foo'})
+>>> f.create()
+Traceback (most recent call last):
+...
+ValueError: The Category could not be created because the data didn't validate.
+
+Create a couple of Writers.
+>>> w = Writer(name='Mike Royko')
+>>> w.save()
+>>> w = Writer(name='Bob Woodward')
+>>> w.save()
+
+ManyToManyFields are represented by a MultipleChoiceField, and ForeignKeys are
+represented by a ChoiceField.
+>>> ArticleForm = form_for_model(Article)
+>>> f = ArticleForm(auto_id=False)
+>>> print f
+<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
+<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
+<tr><th>Writer:</th><td><select name="writer">
+<option value="" selected="selected">---------</option>
+<option value="1">Mike Royko</option>
+<option value="2">Bob Woodward</option>
+</select></td></tr>
+<tr><th>Categories:</th><td><select multiple="multiple" name="categories">
+<option value="1">Entertainment</option>
+<option value="2">It&#39;s a test</option>
+<option value="3">Third test</option>
+</select></td></tr>
+
+You can pass a custom Form class to form_for_model. Make sure it's a
+subclass of BaseForm, not Form.
+>>> class CustomForm(BaseForm):
+... def say_hello(self):
+... print 'hello'
+>>> CategoryForm = form_for_model(Category, form=CustomForm)
+>>> f = CategoryForm()
+>>> f.say_hello()
+hello
+
+Use form_for_instance to create a Form from a model instance. There are two
+differences between this Form and one created via form_for_model. First, the
+object's current values are inserted as 'initial' data in each Field. Second,
+the Form gets an apply_changes() method instead of a create() method.
+>>> w = Writer.objects.get(name='Mike Royko')
+>>> RoykoForm = form_for_instance(w)
+>>> f = RoykoForm(auto_id=False)
+>>> print f
+<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /></td></tr>
+
+>>> art = Article(headline='Test article', pub_date=datetime.date(1988, 1, 4), writer=w)
+>>> art.save()
+>>> art.id
+1
+>>> TestArticleForm = form_for_instance(art)
+>>> f = TestArticleForm(auto_id=False)
+>>> print f.as_ul()
+<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li>
+<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
+<li>Writer: <select name="writer">
+<option value="">---------</option>
+<option value="1" selected="selected">Mike Royko</option>
+<option value="2">Bob Woodward</option>
+</select></li>
+<li>Categories: <select multiple="multiple" name="categories">
+<option value="1">Entertainment</option>
+<option value="2">It&#39;s a test</option>
+<option value="3">Third test</option>
+</select></li>
+>>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', 'writer': u'1'})
+>>> f.is_valid()
+True
+>>> new_art = f.apply_changes()
+>>> new_art.id
+1
+>>> new_art = Article.objects.get(id=1)
+>>> new_art.headline
+'New headline'
"""}
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index c75cedab14..79a320c131 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -514,6 +514,25 @@ beatle J P Paul False
beatle J G George False
beatle J R Ringo False
+A RadioFieldRenderer object also allows index access to individual RadioInput
+objects.
+>>> w = RadioSelect()
+>>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+>>> print r[1]
+<label><input type="radio" name="beatle" value="P" /> Paul</label>
+>>> print r[0]
+<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
+>>> r[0].is_checked()
+True
+>>> r[1].is_checked()
+False
+>>> r[1].name, r[1].value, r[1].choice_value, r[1].choice_label
+('beatle', u'J', 'P', 'Paul')
+>>> r[10]
+Traceback (most recent call last):
+...
+IndexError: list index out of range
+
# CheckboxSelectMultiple Widget ###############################################
>>> w = CheckboxSelectMultiple()
@@ -639,6 +658,8 @@ Each Field's __init__() takes at least these parameters:
label -- A verbose name for this field, for use in displaying this field in
a form. By default, Django will use a "pretty" version of the form
field name, if the Field is part of a Form.
+ initial -- A value to use in this Field's initial display. This value is
+ *not* used as a fallback if data isn't given.
Other than that, the Field subclasses have class-specific options for
__init__(). For example, CharField has a max_length option.
@@ -687,9 +708,21 @@ ValidationError: [u'Ensure this value has at most 10 characters.']
CharField accepts an optional min_length parameter:
>>> f = CharField(min_length=10, required=False)
>>> f.clean('')
+u''
+>>> f.clean('12345')
Traceback (most recent call last):
...
ValidationError: [u'Ensure this value has at least 10 characters.']
+>>> f.clean('1234567890')
+u'1234567890'
+>>> f.clean('1234567890a')
+u'1234567890a'
+
+>>> f = CharField(min_length=10, required=True)
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
>>> f.clean('12345')
Traceback (most recent call last):
...
@@ -757,6 +790,71 @@ Traceback (most recent call last):
...
ValidationError: [u'Enter a whole number.']
+IntegerField accepts an optional max_value parameter:
+>>> f = IntegerField(max_value=10)
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(1)
+1
+>>> f.clean(10)
+10
+>>> f.clean(11)
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 10.']
+>>> f.clean('10')
+10
+>>> f.clean('11')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 10.']
+
+IntegerField accepts an optional min_value parameter:
+>>> f = IntegerField(min_value=10)
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(1)
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is greater than or equal to 10.']
+>>> f.clean(10)
+10
+>>> f.clean(11)
+11
+>>> f.clean('10')
+10
+>>> f.clean('11')
+11
+
+min_value and max_value can be used together:
+>>> f = IntegerField(min_value=10, max_value=20)
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(1)
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is greater than or equal to 10.']
+>>> f.clean(10)
+10
+>>> f.clean(11)
+11
+>>> f.clean('10')
+10
+>>> f.clean('11')
+11
+>>> f.clean(20)
+20
+>>> f.clean(21)
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 20.']
+
# DateField ###################################################################
>>> import datetime
@@ -1002,7 +1100,7 @@ Traceback (most recent call last):
ValidationError: [u'Enter a valid value.']
RegexField takes an optional error_message argument:
->>> f = RegexField('^\d\d\d\d$', 'Enter a four-digit number.')
+>>> f = RegexField('^\d\d\d\d$', error_message='Enter a four-digit number.')
>>> f.clean('1234')
u'1234'
>>> f.clean('123')
@@ -1014,6 +1112,29 @@ Traceback (most recent call last):
...
ValidationError: [u'Enter a four-digit number.']
+RegexField also access min_length and max_length parameters, for convenience.
+>>> f = RegexField('^\d+$', min_length=5, max_length=10)
+>>> f.clean('123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 5 characters.']
+>>> f.clean('abc')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 5 characters.']
+>>> f.clean('12345')
+u'12345'
+>>> f.clean('1234567890')
+u'1234567890'
+>>> f.clean('12345678901')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 10 characters.']
+>>> f.clean('12345a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+
# EmailField ##################################################################
>>> f = EmailField()
@@ -1060,6 +1181,19 @@ Traceback (most recent call last):
...
ValidationError: [u'Enter a valid e-mail address.']
+EmailField also access min_length and max_length parameters, for convenience.
+>>> f = EmailField(min_length=10, max_length=15)
+>>> f.clean('a@foo.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 10 characters.']
+>>> f.clean('alf@foo.com')
+u'alf@foo.com'
+>>> f.clean('alf123456788@foo.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 15 characters.']
+
# URLField ##################################################################
>>> f = URLField()
@@ -1152,6 +1286,19 @@ Traceback (most recent call last):
...
ValidationError: [u'This URL appears to be a broken link.']
+EmailField also access min_length and max_length parameters, for convenience.
+>>> f = URLField(min_length=15, max_length=20)
+>>> f.clean('http://f.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 15 characters.']
+>>> f.clean('http://example.com')
+u'http://example.com'
+>>> f.clean('http://abcdefghijklmnopqrstuvwxyz.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 20 characters.']
+
# BooleanField ################################################################
>>> f = BooleanField()
@@ -1398,19 +1545,13 @@ Empty dictionaries are valid, too.
>>> p.is_valid()
False
>>> print p
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" id="id_first_name" /></td></tr>
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" id="id_birthday" /></td></tr>
+<tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="first_name" id="id_first_name" /></td></tr>
+<tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="last_name" id="id_last_name" /></td></tr>
+<tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="birthday" id="id_birthday" /></td></tr>
>>> print p.as_table()
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" id="id_first_name" /></td></tr>
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" id="id_birthday" /></td></tr>
+<tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="first_name" id="id_first_name" /></td></tr>
+<tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="last_name" id="id_last_name" /></td></tr>
+<tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="birthday" id="id_birthday" /></td></tr>
>>> print p.as_ul()
<li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li>
<li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li>
@@ -1799,12 +1940,9 @@ Form.clean() is required to return a dictionary of all clean data.
{}
>>> f = UserRegistration({}, auto_id=False)
>>> print f.as_table()
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th>Username:</th><td><input type="text" name="username" maxlength="10" /></td></tr>
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th>Password1:</th><td><input type="password" name="password1" /></td></tr>
-<tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr>
-<tr><th>Password2:</th><td><input type="password" name="password2" /></td></tr>
+<tr><th>Username:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="username" maxlength="10" /></td></tr>
+<tr><th>Password1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password1" /></td></tr>
+<tr><th>Password2:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password2" /></td></tr>
>>> f.errors
{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']}
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
@@ -1972,6 +2110,8 @@ in "attrs".
<li>Username: <input type="text" name="username" maxlength="10" /></li>
<li>Password: <input type="password" name="password" maxlength="10" /></li>
+# Specifying labels ###########################################################
+
You can specify the label for a field by using the 'label' argument to a Field
class. If you don't specify 'label', Django will use the field name with
underscores converted to spaces, and the initial letter capitalized.
@@ -1985,6 +2125,81 @@ underscores converted to spaces, and the initial letter capitalized.
<li>Password1: <input type="password" name="password1" /></li>
<li>Password (again): <input type="password" name="password2" /></li>
+A label can be a Unicode object or a bytestring with special characters.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, label='ŠĐĆŽćžšđ')
+... password = CharField(widget=PasswordInput, label=u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111')
+>>> p = UserRegistration(auto_id=False)
+>>> p.as_ul()
+u'<li>\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111: <input type="text" name="username" maxlength="10" /></li>\n<li>\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111: <input type="password" name="password" /></li>'
+
+If a label is set to the empty string for a field, that field won't get a label.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, label='')
+... password = CharField(widget=PasswordInput)
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+<li> <input type="text" name="username" maxlength="10" /></li>
+<li>Password: <input type="password" name="password" /></li>
+>>> p = UserRegistration(auto_id='id_%s')
+>>> print p.as_ul()
+<li> <input id="id_username" type="text" name="username" maxlength="10" /></li>
+<li><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></li>
+
+If label is None, Django will auto-create the label from the field name. This
+is default behavior.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, label=None)
+... password = CharField(widget=PasswordInput)
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+<li>Username: <input type="text" name="username" maxlength="10" /></li>
+<li>Password: <input type="password" name="password" /></li>
+>>> p = UserRegistration(auto_id='id_%s')
+>>> print p.as_ul()
+<li><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="10" /></li>
+<li><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></li>
+
+# Initial data ################################################################
+
+You can specify initial data for a field by using the 'initial' argument to a
+Field class. This initial data is displayed when a Form is rendered with *no*
+data. It is not displayed when a Form is rendered with any data (including an
+empty dictionary). Also, the initial value is *not* used if data for a
+particular required field isn't provided.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, initial='django')
+... password = CharField(widget=PasswordInput)
+
+Here, we're not submitting any data, so the initial value will be displayed.
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
+<li>Password: <input type="password" name="password" /></li>
+
+Here, we're submitting data, so the initial value will *not* be displayed.
+>>> p = UserRegistration({}, auto_id=False)
+>>> print p.as_ul()
+<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
+<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
+>>> p = UserRegistration({'username': u''}, auto_id=False)
+>>> print p.as_ul()
+<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
+<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
+>>> p = UserRegistration({'username': u'foo'}, auto_id=False)
+>>> print p.as_ul()
+<li>Username: <input type="text" name="username" value="foo" maxlength="10" /></li>
+<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
+
+An 'initial' value is *not* used as a fallback if data is not provided. In this
+example, we don't provide a value for 'username', and the form raises a
+validation error rather than using the initial value for 'username'.
+>>> p = UserRegistration({'password': 'secret'})
+>>> p.errors
+{'username': [u'This field is required.']}
+>>> p.is_valid()
+False
+
# Forms with prefixes #########################################################
Sometimes it's necessary to have multiple forms display on the same HTML page,
@@ -2133,8 +2348,7 @@ Case 2: POST with erroneous data (a redisplayed form, with errors).
<form action="" method="post">
<table>
<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
-<tr><td colspan="2"><ul class="errorlist"><li>Ensure this value has at most 10 characters.</li></ul></td></tr>
-<tr><th>Username:</th><td><input type="text" name="username" value="this-is-a-long-username" maxlength="10" /></td></tr>
+<tr><th>Username:</th><td><ul class="errorlist"><li>Ensure this value has at most 10 characters.</li></ul><input type="text" name="username" value="this-is-a-long-username" maxlength="10" /></td></tr>
<tr><th>Password1:</th><td><input type="password" name="password1" value="foo" /></td></tr>
<tr><th>Password2:</th><td><input type="password" name="password2" value="bar" /></td></tr>
</table>
@@ -2257,6 +2471,141 @@ the list of errors is empty). You can also use it in {% if %} statements.
<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
<input type="submit" />
</form>
+
+#################
+# Extra widgets #
+#################
+
+The newforms library comes with some extra, higher-level Widget classes that
+demonstrate some of the library's abilities.
+
+# SelectDateWidget ############################################################
+
+>>> from django.newforms.extras import SelectDateWidget
+>>> w = SelectDateWidget()
+>>> print w.render('mydate', '')
+<select name="mydate_month">
+<option value="1">January</option>
+<option value="2">February</option>
+<option value="3">March</option>
+<option value="4">April</option>
+<option value="5">May</option>
+<option value="6">June</option>
+<option value="7">July</option>
+<option value="8">August</option>
+<option value="9">September</option>
+<option value="10">October</option>
+<option value="11">November</option>
+<option value="12">December</option>
+</select>
+<select name="mydate_day">
+<option value="1">1</option>
+<option value="2">2</option>
+<option value="3">3</option>
+<option value="4">4</option>
+<option value="5">5</option>
+<option value="6">6</option>
+<option value="7">7</option>
+<option value="8">8</option>
+<option value="9">9</option>
+<option value="10">10</option>
+<option value="11">11</option>
+<option value="12">12</option>
+<option value="13">13</option>
+<option value="14">14</option>
+<option value="15">15</option>
+<option value="16">16</option>
+<option value="17">17</option>
+<option value="18">18</option>
+<option value="19">19</option>
+<option value="20">20</option>
+<option value="21">21</option>
+<option value="22">22</option>
+<option value="23">23</option>
+<option value="24">24</option>
+<option value="25">25</option>
+<option value="26">26</option>
+<option value="27">27</option>
+<option value="28">28</option>
+<option value="29">29</option>
+<option value="30">30</option>
+<option value="31">31</option>
+</select>
+<select name="mydate_year">
+<option value="2006">2006</option>
+<option value="2007">2007</option>
+<option value="2008">2008</option>
+<option value="2009">2009</option>
+<option value="2010">2010</option>
+<option value="2011">2011</option>
+<option value="2012">2012</option>
+<option value="2013">2013</option>
+<option value="2014">2014</option>
+<option value="2015">2015</option>
+</select>
+>>> w.render('mydate', None) == w.render('mydate', '')
+True
+>>> print w.render('mydate', '2010-04-15')
+<select name="mydate_month">
+<option value="1">January</option>
+<option value="2">February</option>
+<option value="3">March</option>
+<option value="4" selected="selected">April</option>
+<option value="5">May</option>
+<option value="6">June</option>
+<option value="7">July</option>
+<option value="8">August</option>
+<option value="9">September</option>
+<option value="10">October</option>
+<option value="11">November</option>
+<option value="12">December</option>
+</select>
+<select name="mydate_day">
+<option value="1">1</option>
+<option value="2">2</option>
+<option value="3">3</option>
+<option value="4">4</option>
+<option value="5">5</option>
+<option value="6">6</option>
+<option value="7">7</option>
+<option value="8">8</option>
+<option value="9">9</option>
+<option value="10">10</option>
+<option value="11">11</option>
+<option value="12">12</option>
+<option value="13">13</option>
+<option value="14">14</option>
+<option value="15" selected="selected">15</option>
+<option value="16">16</option>
+<option value="17">17</option>
+<option value="18">18</option>
+<option value="19">19</option>
+<option value="20">20</option>
+<option value="21">21</option>
+<option value="22">22</option>
+<option value="23">23</option>
+<option value="24">24</option>
+<option value="25">25</option>
+<option value="26">26</option>
+<option value="27">27</option>
+<option value="28">28</option>
+<option value="29">29</option>
+<option value="30">30</option>
+<option value="31">31</option>
+</select>
+<select name="mydate_year">
+<option value="2006">2006</option>
+<option value="2007">2007</option>
+<option value="2008">2008</option>
+<option value="2009">2009</option>
+<option value="2010" selected="selected">2010</option>
+<option value="2011">2011</option>
+<option value="2012">2012</option>
+<option value="2013">2013</option>
+<option value="2014">2014</option>
+<option value="2015">2015</option>
+</select>
+
"""
if __name__ == "__main__":