Django

Code

Show
Ignore:
Timestamp:
01/31/07 17:43:09 (2 years ago)
Author:
rmunn
Message:

Merged revisions 4186 to 4454 from trunk.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/sqlalchemy/tests/modeltests/basic/models.py

    r3832 r4455  
    1111    pub_date = models.DateTimeField() 
    1212 
     13    class Meta: 
     14        ordering = ('pub_date','headline') 
     15         
    1316    def __str__(self): 
    1417        return self.headline 
     
    246249# Slices (without step) are lazy: 
    247250>>> Article.objects.all()[0:5].filter() 
    248 [<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Fourth article>, <Article: Article 6>] 
     251[<Article: Area woman programs in Python>, <Article: Second article>, <Article: Third article>, <Article: Article 6>, <Article: Default headline>] 
    249252 
    250253# Slicing again works: 
     
    254257[<Article: Area woman programs in Python>, <Article: Second article>] 
    255258>>> Article.objects.all()[0:5][4:] 
    256 [<Article: Article 6>] 
     259[<Article: Default headline>] 
    257260>>> Article.objects.all()[0:5][5:] 
    258261[] 
     
    260263# Some more tests! 
    261264>>> Article.objects.all()[2:][0:2] 
    262 [<Article: Third article>, <Article: Fourth article>] 
     265[<Article: Third article>, <Article: Article 6>] 
    263266>>> Article.objects.all()[2:][:2] 
    264 [<Article: Third article>, <Article: Fourth article>] 
     267[<Article: Third article>, <Article: Article 6>] 
    265268>>> Article.objects.all()[2:][2:3] 
    266 [<Article: Article 6>] 
     269[<Article: Default headline>] 
    267270 
    268271# Note that you can't use 'offset' without 'limit' (on some dbs), so this doesn't work: 
     
    313316# Bulk delete test: How many objects before and after the delete? 
    314317>>> Article.objects.all() 
    315 [<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>] 
     318[<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>] 
    316319>>> Article.objects.filter(id__lte=4).delete() 
    317320>>> Article.objects.all() 
  • django/branches/sqlalchemy/tests/modeltests/custom_columns/models.py

    r3661 r4455  
    11""" 
    2 17. Custom column names 
     217. Custom column/table names 
    33 
    44If your database column name is different than your model attribute, use the 
    55``db_column`` parameter. Note that you'll use the field's name, not its column 
    66name, in API usage. 
     7 
     8If your database table name is different than your model name, use the 
     9``db_table`` Meta attribute. This has no effect on the API used to  
     10query the database. 
     11 
     12If you need to use a table name for a many-to-many relationship that differs  
     13from the default generated name, use the ``db_table`` parameter on the  
     14ManyToMany field. This has no effect on the API for querying the database. 
     15 
    716""" 
    817 
    918from django.db import models 
    1019 
    11 class Person(models.Model): 
     20class Author(models.Model): 
    1221    first_name = models.CharField(maxlength=30, db_column='firstname') 
    1322    last_name = models.CharField(maxlength=30, db_column='last') 
     
    1625        return '%s %s' % (self.first_name, self.last_name) 
    1726 
     27    class Meta: 
     28        db_table = 'my_author_table' 
     29        ordering = ('last_name','first_name') 
     30 
     31class Article(models.Model): 
     32    headline = models.CharField(maxlength=100) 
     33    authors = models.ManyToManyField(Author, db_table='my_m2m_table') 
     34 
     35    def __str__(self): 
     36        return self.headline 
     37 
     38    class Meta: 
     39        ordering = ('headline',) 
     40         
    1841__test__ = {'API_TESTS':""" 
    19 # Create a Person
    20 >>> p = Person(first_name='John', last_name='Smith') 
    21 >>> p.save() 
     42# Create a Author
     43>>> a = Author(first_name='John', last_name='Smith') 
     44>>> a.save() 
    2245 
    23 >>> p.id 
     46>>> a.id 
    24471 
    2548 
    26 >>> Person.objects.all() 
    27 [<Person: John Smith>] 
     49# Create another author 
     50>>> a2 = Author(first_name='Peter', last_name='Jones') 
     51>>> a2.save() 
    2852 
    29 >>> Person.objects.filter(first_name__exact='John') 
    30 [<Person: John Smith>] 
     53# Create an article 
     54>>> art = Article(headline='Django lets you build web apps easily') 
     55>>> art.save() 
     56>>> art.authors = [a, a2] 
    3157 
    32 >>> Person.objects.get(first_name__exact='John') 
    33 <Person: John Smith> 
     58# Although the table and column names on Author have been set to  
     59# custom values, nothing about using the Author model has changed... 
    3460 
    35 >>> Person.objects.filter(firstname__exact='John') 
     61# Query the available authors 
     62>>> Author.objects.all() 
     63[<Author: Peter Jones>, <Author: John Smith>] 
     64 
     65>>> Author.objects.filter(first_name__exact='John') 
     66[<Author: John Smith>] 
     67 
     68>>> Author.objects.get(first_name__exact='John') 
     69<Author: John Smith> 
     70 
     71>>> Author.objects.filter(firstname__exact='John') 
    3672Traceback (most recent call last): 
    3773    ... 
    3874TypeError: Cannot resolve keyword 'firstname' into field 
    3975 
    40 >>> p = Person.objects.get(last_name__exact='Smith') 
    41 >>> p.first_name 
     76>>> a = Author.objects.get(last_name__exact='Smith') 
     77>>> a.first_name 
    4278'John' 
    43 >>> p.last_name 
     79>>> a.last_name 
    4480'Smith' 
    45 >>> p.firstname 
     81>>> a.firstname 
    4682Traceback (most recent call last): 
    4783    ... 
    48 AttributeError: 'Person' object has no attribute 'firstname' 
    49 >>> p.last 
     84AttributeError: 'Author' object has no attribute 'firstname' 
     85>>> a.last 
    5086Traceback (most recent call last): 
    5187    ... 
    52 AttributeError: 'Person' object has no attribute 'last' 
     88AttributeError: 'Author' object has no attribute 'last' 
     89 
     90# Although the Article table uses a custom m2m table,  
     91# nothing about using the m2m relationship has changed... 
     92 
     93# Get all the authors for an article 
     94>>> art.authors.all() 
     95[<Author: Peter Jones>, <Author: John Smith>] 
     96 
     97# Get the articles for an author 
     98>>> a.article_set.all() 
     99[<Article: Django lets you build web apps easily>] 
     100 
     101# Query the authors across the m2m relation 
     102>>> art.authors.filter(last_name='Jones') 
     103[<Author: Peter Jones>] 
     104 
    53105"""} 
  • django/branches/sqlalchemy/tests/modeltests/generic_relations/models.py

    r3661 r4455  
    6666# Objects with declared GenericRelations can be tagged directly -- the API 
    6767# mimics the many-to-many API. 
     68>>> bacon.tags.create(tag="fatty") 
     69<TaggedItem: fatty> 
     70>>> bacon.tags.create(tag="salty") 
     71<TaggedItem: salty> 
    6872>>> lion.tags.create(tag="yellow") 
    6973<TaggedItem: yellow> 
    7074>>> lion.tags.create(tag="hairy") 
    7175<TaggedItem: hairy> 
    72 >>> bacon.tags.create(tag="fatty") 
    73 <TaggedItem: fatty> 
    74 >>> bacon.tags.create(tag="salty") 
    75 <TaggedItem: salty> 
    7676 
    7777>>> lion.tags.all() 
     
    106106>>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id) 
    107107[<TaggedItem: clearish>] 
     108 
     109# If you delete an object with an explicit Generic relation, the related 
     110# objects are deleted when the source object is deleted. 
     111# Original list of tags: 
     112>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 
     113[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('hairy', <ContentType: animal>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2), ('yellow', <ContentType: animal>, 1)] 
     114 
     115>>> lion.delete() 
     116>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 
     117[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 
     118 
     119# If Generic Relation is not explicitly defined, any related objects  
     120# remain after deletion of the source object. 
     121>>> quartz.delete() 
     122>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 
     123[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 
     124 
     125# If you delete a tag, the objects using the tag are unaffected  
     126# (other than losing a tag) 
     127>>> tag = TaggedItem.objects.get(id=1) 
     128>>> tag.delete() 
     129>>> bacon.tags.all() 
     130[<TaggedItem: salty>] 
     131>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()] 
     132[('clearish', <ContentType: mineral>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 
     133 
    108134"""} 
  • django/branches/sqlalchemy/tests/modeltests/lookup/models.py

    r3661 r4455  
    192192[<Article: Article with \ backslash>] 
    193193 
     194# none() returns an EmptyQuerySet that behaves like any other QuerySet object 
     195>>> Article.objects.none() 
     196[] 
     197>>> Article.objects.none().filter(headline__startswith='Article') 
     198[] 
     199>>> Article.objects.none().count() 
     2000 
     201 
     202# using __in with an empty list should return an empty query set 
     203>>> Article.objects.filter(id__in=[]) 
     204[] 
     205 
     206>>> Article.objects.exclude(id__in=[]) 
     207[<Article: Article with \ backslash>, <Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] 
     208 
    194209"""} 
  • django/branches/sqlalchemy/tests/modeltests/many_to_many/models.py

    r3661 r4455  
    204204[<Article: Oxygen-free diet works wonders>] 
    205205 
    206 # Recreate the article and Publication we just deleted. 
     206# Relation sets can also be set using primary key values 
     207>>> p2.article_set = [a4.id, a5.id] 
     208>>> p2.article_set.all() 
     209[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>] 
     210>>> a4.publications.all() 
     211[<Publication: Science News>] 
     212>>> a4.publications = [p3.id] 
     213>>> p2.article_set.all() 
     214[<Article: Oxygen-free diet works wonders>] 
     215>>> a4.publications.all() 
     216[<Publication: Science Weekly>] 
     217 
     218# Recreate the article and Publication we have deleted. 
    207219>>> p1 = Publication(id=None, title='The Python Journal') 
    208220>>> p1.save() 
     
    232244[<Article: NASA uses Python>] 
    233245 
     246# An alternate to calling clear() is to assign the empty set 
     247>>> p1.article_set = [] 
     248>>> p1.article_set.all() 
     249[] 
     250 
     251>>> a2.publications = [p1, new_publication] 
     252>>> a2.publications.all() 
     253[<Publication: Highlights for Children>, <Publication: The Python Journal>] 
     254>>> a2.publications = [] 
     255>>> a2.publications.all() 
     256[] 
     257 
    234258"""} 
  • django/branches/sqlalchemy/tests/modeltests/or_lookups/models.py

    r3661 r4455  
    7070[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>] 
    7171 
     72# You could also use "in" to accomplish the same as above. 
     73>>> Article.objects.filter(pk__in=[1,2,3]) 
     74[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>] 
     75 
     76>>> Article.objects.filter(pk__in=[1,2,3,4]) 
     77[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>] 
     78 
     79# Passing "in" an empty list returns no results ... 
     80>>> Article.objects.filter(pk__in=[]) 
     81[] 
     82 
     83# ... but can return results if we OR it with another query. 
     84>>> Article.objects.filter(Q(pk__in=[]) | Q(headline__icontains='goodbye')) 
     85[<Article: Goodbye>, <Article: Hello and goodbye>] 
     86 
    7287# Q arg objects are ANDed 
    7388>>> Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye')) 
  • django/branches/sqlalchemy/tests/modeltests/serializers/models.py

    r3661 r4455  
    3737    def __str__(self): 
    3838        return self.headline 
     39 
     40class AuthorProfile(models.Model): 
     41    author = models.OneToOneField(Author) 
     42    date_of_birth = models.DateField() 
     43     
     44    def __str__(self): 
     45        return "Profile of %s" % self.author 
    3946 
    4047__test__ = {'API_TESTS':""" 
     
    119126[<Article: Just kidding; I love TV poker>, <Article: Time to reform copyright>] 
    120127 
     128# If you use your own primary key field (such as a OneToOneField),  
     129# it doesn't appear in the serialized field list - it replaces the 
     130# pk identifier. 
     131>>> profile = AuthorProfile(author=joe, date_of_birth=datetime(1970,1,1)) 
     132>>> profile.save() 
     133 
     134>>> json = serializers.serialize("json", AuthorProfile.objects.all()) 
     135>>> json 
     136'[{"pk": "1", "model": "serializers.authorprofile", "fields": {"date_of_birth": "1970-01-01"}}]' 
     137 
     138>>> for obj in serializers.deserialize("json", json): 
     139...     print obj 
     140<DeserializedObject: Profile of Joe> 
     141 
    121142"""} 
  • django/branches/sqlalchemy/tests/modeltests/test_client/views.py

    r3724 r4455  
    2727    return HttpResponseRedirect('/test_client/get_view/') 
    2828     
    29 @login_required 
    3029def login_protected_view(request): 
    3130    "A simple view that is login protected." 
     
    3433     
    3534    return HttpResponse(t.render(c)) 
     35login_protected_view = login_required(login_protected_view) 
  • django/branches/sqlalchemy/tests/regressiontests/defaultfilters/tests.py

    r3832 r4455  
    1212>>> floatformat(0.0) 
    1313'0' 
     14>>> floatformat(7.7,3) 
     15'7.700' 
     16>>> floatformat(6.000000,3) 
     17'6.000' 
     18>>> floatformat(13.1031,-3) 
     19'13.103' 
     20>>> floatformat(11.1197, -2) 
     21'11.12' 
     22>>> floatformat(11.0000, -2) 
     23'11' 
     24>>> floatformat(11.000001, -2) 
     25'11.00' 
     26>>> floatformat(8.2798, 3) 
     27'8.280' 
     28>>> floatformat('foo') 
     29'' 
     30>>> floatformat(13.1031, 'bar') 
     31'13.1031' 
     32>>> floatformat('foo', 'bar') 
     33'' 
    1434 
    1535>>> addslashes('"double quotes" and \'single quotes\'') 
  • django/branches/sqlalchemy/tests/regressiontests/forms/tests.py

    r4186 r4455  
    107107u'<input type="hidden" class="special" name="email" />' 
    108108 
     109# MultipleHiddenInput Widget ################################################## 
     110 
     111>>> w = MultipleHiddenInput() 
     112>>> w.render('email', []) 
     113u'' 
     114>>> w.render('email', None) 
     115u'' 
     116>>> w.render('email', ['test@example.com']) 
     117u'<input type="hidden" name="email" value="test@example.com" />' 
     118>>> w.render('email', ['some "quoted" & ampersanded value']) 
     119u'<input type="hidden" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />' 
     120>>> w.render('email', ['test@example.com', 'foo@example.com']) 
     121u'<input type="hidden" name="email" value="test@example.com" />\n<input type="hidden" name="email" value="foo@example.com" />' 
     122>>> w.render('email', ['test@example.com'], attrs={'class': 'fun'}) 
     123u'<input type="hidden" name="email" value="test@example.com" class="fun" />' 
     124>>> w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'}) 
     125u'<input type="hidden" name="email" value="test@example.com" class="fun" />\n<input type="hidden" name="email" value="foo@example.com" class="fun" />' 
     126 
     127You can also pass 'attrs' to the constructor: 
     128>>> w = MultipleHiddenInput(attrs={'class': 'fun'}) 
     129>>> w.render('email', []) 
     130u'' 
     131>>> w.render('email', ['foo@example.com']) 
     132u'<input type="hidden" class="fun" value="foo@example.com" name="email" />' 
     133>>> w.render('email', ['foo@example.com', 'test@example.com']) 
     134u'<input type="hidden" class="fun" value="foo@example.com" name="email" />\n<input type="hidden" class="fun" value="test@example.com" name="email" />' 
     135 
     136'attrs' passed to render() get precedence over those passed to the constructor: 
     137>>> w = MultipleHiddenInput(attrs={'class': 'pretty'}) 
     138>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'}) 
     139u'<input type="hidden" class="special" value="foo@example.com" name="email" />' 
     140 
     141>>> w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'}) 
     142u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />' 
     143 
     144'attrs' passed to render() get precedence over those passed to the constructor: 
     145>>> w = MultipleHiddenInput(attrs={'class': 'pretty'}) 
     146>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'}) 
     147u'<input type="hidden" class="special" value="foo@example.com" name="email" />' 
     148 
    109149# FileInput Widget ############################################################ 
    110150 
     
    296336>>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]) 
    297337u'<select name="email">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>' 
     338 
     339If choices is passed to the constructor and is a generator, it can be iterated 
     340over multiple times without getting consumed: 
     341>>> w = Select(choices=get_choices()) 
     342>>> print w.render('num', 2) 
     343<select name="num"> 
     344<option value="0">0</option> 
     345<option value="1">1</option> 
     346<option value="2" selected="selected">2</option> 
     347<option value="3">3</option> 
     348<option value="4">4</option> 
     349</select> 
     350>>> print w.render('num', 3) 
     351<select name="num"> 
     352<option value="0">0</option> 
     353<option value="1">1</option> 
     354<option value="2">2</option> 
     355<option value="3" selected="selected">3</option> 
     356<option value="4">4</option> 
     357</select> 
     358 
     359# NullBooleanSelect Widget #################################################### 
     360 
     361>>> w = NullBooleanSelect() 
     362>>> print w.render('is_cool', True) 
     363<select name="is_cool"> 
     364<option value="1">Unknown</option> 
     365<option value="2" selected="selected">Yes</option> 
     366<option value="3">No</option> 
     367</select> 
     368>>> print w.render('is_cool', False) 
     369<select name="is_cool"> 
     370<option value="1">Unknown</option> 
     371<option value="2">Yes</option> 
     372<option value="3" selected="selected">No</option> 
     373</select> 
     374>>> print w.render('is_cool', None) 
     375<select name="is_cool"> 
     376<option value="1" selected="selected">Unknown</option> 
     377<option value="2">Yes</option> 
     378<option value="3">No</option> 
     379</select> 
     380>>> print w.render('is_cool', '2') 
     381<select name="is_cool"> 
     382<option value="1">Unknown</option> 
     383<option value="2" selected="selected">Yes</option> 
     384<option value="3">No</option> 
     385</select> 
     386>>> print w.render('is_cool', '3') 
     387<select name="is_cool"> 
     388<option value="1">Unknown</option> 
     389<option value="2">Yes</option> 
     390<option value="3" selected="selected">No</option> 
     391</select> 
    298392 
    299393# SelectMultiple Widget ####################################################### 
     
    515609beatle J R Ringo False 
    516610 
     611A RadioFieldRenderer object also allows index access to individual RadioInput 
     612objects. 
     613>>> w = RadioSelect() 
     614>>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 
     615>>> print r[1] 
     616<label><input type="radio" name="beatle" value="P" /> Paul</label> 
     617>>> print r[0] 
     618<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label> 
     619>>> r[0].is_checked() 
     620True 
     621>>> r[1].is_checked() 
     622False 
     623>>> r[1].name, r[1].value, r[1].choice_value, r[1].choice_label 
     624('beatle', u'J', u'P', u'Paul') 
     625>>> r[10] 
     626Traceback (most recent call last): 
     627... 
     628IndexError: list index out of range 
     629 
     630>>> w = RadioSelect() 
     631>>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])) 
     632u'<ul>\n<li><label><input checked="checked" type="radio" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="radio" name="email" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>' 
     633 
    517634# CheckboxSelectMultiple Widget ############################################### 
    518635 
     
    622739u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>' 
    623740 
     741# MultiWidget ################################################################# 
     742 
     743>>> class MyMultiWidget(MultiWidget): 
     744...     def decompress(self, value): 
     745...         if value: 
     746...             return value.split('__') 
     747...         return ['', ''] 
     748...     def format_output(self, rendered_widgets): 
     749...         return u'<br />'.join(rendered_widgets) 
     750>>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'}))) 
     751>>> w.render('name', ['john', 'lennon']) 
     752u'<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />' 
     753>>> w.render('name', 'john__lennon') 
     754u'<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />' 
     755 
     756# SplitDateTimeWidget ######################################################### 
     757 
     758>>> w = SplitDateTimeWidget() 
     759>>> w.render('date', '') 
     760u'<input type="text" name="date_0" /><input type="text" name="date_1" />' 
     761>>> w.render('date', None) 
     762u'<input type="text" name="date_0" /><input type="text" name="date_1" />' 
     763>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30)) 
     764u'<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />' 
     765>>> w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)]) 
     766u'<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />' 
     767 
     768You can also pass 'attrs' to the constructor. In this case, the attrs will be 
     769included on both widgets. 
     770>>> w = SplitDateTimeWidget(attrs={'class': 'pretty'}) 
     771>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30)) 
     772u'<input type="text" class="pretty" value="2006-01-10" name="date_0" /><input type="text" class="pretty" value="07:30:00" name="date_1" />' 
     773 
    624774########## 
    625775# Fields # 
     
    637787              Widget that it'll use if you don't specify this. In most cases, 
    638788              the default widget is TextInput. 
     789    label -- A verbose name for this field, for use in displaying this field in 
     790             a form. By default, Django will use a "pretty" version of the form 
     791             field name, if the Field is part of a Form. 
     792    initial -- A value to use in this Field's initial display. This value is 
     793               *not* used as a fallback if data isn't given. 
    639794 
    640795Other than that, the Field subclasses have class-specific options for 
     
    685840>>> f = CharField(min_length=10, required=False) 
    686841>>> f.clean('') 
     842u'' 
     843>>> f.clean('12345') 
    687844Traceback (most recent call last): 
    688845... 
    689846ValidationError: [u'Ensure this value has at least 10 characters.'] 
     847>>> f.clean('1234567890') 
     848u'1234567890' 
     849>>> f.clean('1234567890a') 
     850u'1234567890a' 
     851 
     852>>> f = CharField(min_length=10, required=True) 
     853>>> f.clean('') 
     854Traceback (most recent call last): 
     855... 
     856ValidationError: [u'This field is required.'] 
    690857>>> f.clean('12345') 
    691858Traceback (most recent call last): 
     
    731898>>> f = IntegerField(required=False) 
    732899>>> f.clean('') 
    733 u'' 
     900>>> repr(f.clean('')) 
     901'None' 
    734902>>> f.clean(None) 
    735 u'' 
     903>>> repr(f.clean(None)) 
     904'None' 
    736905>>> f.clean('1') 
    7379061 
     
    754923... 
    755924ValidationError: [u'Enter a whole number.'] 
     925 
     926IntegerField accepts an optional max_value parameter: 
     927>>> f = IntegerField(max_value=10) 
     928>>> f.clean(None) 
     929Traceback (most recent call last): 
     930... 
     931ValidationError: [u'This field is required.'] 
     932>>> f.clean(1) 
     9331 
     934>>> f.clean(10) 
     93510 
     936>>> f.clean(11) 
     937Traceback (most recent call last): 
     938... 
     939ValidationError: [u'Ensure this value is less than or equal to 10.'] 
     940>>> f.clean('10') 
     94110 
     942>>> f.clean('11') 
     943Traceback (most recent call last): 
     944... 
     945ValidationError: [u'Ensure this value is less than or equal to 10.'] 
     946 
     947IntegerField accepts an optional min_value parameter: 
     948>>> f = IntegerField(min_value=10) 
     949>>> f.clean(None) 
     950Traceback (most recent call last): 
     951... 
     952ValidationError: [u'This field is required.'] 
     953>>> f.clean(1) 
     954Traceback (most recent call last): 
     955... 
     956ValidationError: [u'Ensure this value is greater than or equal to 10.'] 
     957>>> f.clean(10) 
     95810 
     959>>> f.clean(11) 
     96011 
     961>>> f.clean('10') 
     96210 
     963>>> f.clean('11') 
     96411 
     965 
     966min_value and max_value can be used together: 
     967>>> f = IntegerField(min_value=10, max_value=20) 
     968>>> f.clean(None) 
     969Traceback (most recent call last): 
     970... 
     971ValidationError: [u'This field is required.'] 
     972>>> f.clean(1) 
     973Traceback (most recent call last): 
     974... 
     975ValidationError: [u'Ensure this value is greater than or equal to 10.'] 
     976>>> f.clean(10) 
     97710 
     978>>> f.clean(11) 
     97911 
     980>>> f.clean('10') 
     98110 
     982>>> f.clean('11') 
     98311 
     984>>> f.clean(20) 
     98520 
     986>>> f.clean(21) 
     987Traceback (most recent call last): 
     988... 
     989ValidationError: [u'Ensure this value is less than or equal to 20.'] 
    756990 
    757991# DateField ################################################################### 
     
    8311065... 
    8321066ValidationError: [u'Enter a valid date.'] 
     1067 
     1068# TimeField ################################################################### 
     1069 
     1070>>> import datetime 
     1071>>> f = TimeField() 
     1072>>> f.clean(datetime.time(14, 25)) 
     1073datetime.time(14, 25) 
     1074>>> f.clean(datetime.time(14, 25, 59)) 
     1075datetime.time(14, 25, 59) 
     1076>>> f.clean('14:25') 
     1077datetime.time(14, 25) 
     1078>>> f.clean('14:25:59') 
     1079datetime.time(14, 25, 59) 
     1080>>> f.clean('hello') 
     1081Traceback (most recent call last): 
     1082... 
     1083ValidationError: [u'Enter a valid time.'] 
     1084>>> f.clean('1:24 p.m.') 
     1085Traceback (most recent call last): 
     1086... 
     1087ValidationError: [u'Enter a valid time.'] 
     1088 
     1089TimeField accepts an optional input_formats parameter: 
     1090>>> f = TimeField(input_formats=['%I:%M %p']) 
     1091>>> f.clean(datetime.time(14, 25)) 
     1092datetime.time(14, 25) 
     1093>>> f.clean(datetime.time(14, 25, 59)) 
     1094datetime.time(14, 25, 59) 
     1095>>> f.clean('4:25 AM') 
     1096datetime.time(4, 25) 
     1097>>> f.clean('4:25 PM') 
     1098datetime.time(16, 25) 
     1099 
     1100The input_formats parameter overrides all default input formats, 
     1101so the default formats won't work unless you specify them: 
     1102>>> f.clean('14:30:45') 
     1103Traceback (most recent call last): 
     1104... 
     1105ValidationError: [u'Enter a valid time.'] 
    8331106 
    8341107# DateTimeField ############################################################### 
     
    9611234 
    9621235RegexField takes an optional error_message argument: 
    963 >>> f = RegexField('^\d\d\d\d$', 'Enter a four-digit number.') 
     1236>>> f = RegexField('^\d\d\d\d$', error_message='Enter a four-digit number.') 
    9641237>>> f.clean('1234') 
    9651238u'1234' 
     
    9721245... 
    9731246ValidationError: [u'Enter a four-digit number.'] 
     1247 
     1248RegexField also access min_length and max_length parameters, for convenience. 
     1249>>> f = RegexField('^\d+$', min_length=5, max_length=10) 
     1250>>> f.clean('123') 
     1251Traceback (most recent call last): 
     1252... 
     1253ValidationError: [u'Ensure this value has at least 5 characters.'] 
     1254>>> f.clean('abc') 
     1255Traceback (most recent call last): 
     1256... 
     1257ValidationError: [u'Ensure this value has at least 5 characters.'] 
     1258>>> f.clean('12345') 
     1259u'12345' 
     1260>>> f.clean('1234567890') 
     1261u'1234567890' 
     1262>>> f.clean('12345678901') 
     1263Traceback (most recent call last): 
     1264... 
     1265ValidationError: [u'Ensure this value has at most 10 characters.'] 
     1266>>> f.clean('12345a') 
     1267Traceback (most recent call last): 
     1268... 
     1269ValidationError: [u'Enter a valid value.'] 
    9741270 
    9751271# EmailField ################################################################## 
     
    10181314... 
    10191315ValidationError: [u'Enter a valid e-mail address.'] 
     1316 
     1317EmailField also access min_length and max_length parameters, for convenience. 
     1318>>> f = EmailField(min_length=10, max_length=15) 
     1319>>> f.clean('a@foo.com') 
     1320Traceback (most recent call last): 
     1321... 
     1322ValidationError: [u'Ensure this value has at least 10 characters.'] 
     1323>>> f.clean('alf@foo.com') 
     1324u'alf@foo.com' 
     1325>>> f.clean('alf123456788@foo.com') 
     1326Traceback (most recent call last): 
     1327... 
     1328ValidationError: [u'Ensure this value has at most 15 characters.'] 
    10201329 
    10211330# URLField ################################################################## 
     
    11101419... 
    11111420ValidationError: [u'This URL appears to be a broken link.'] 
     1421>>> f = URLField(verify_exists=True, required=False) 
     1422>>> f.clean('') 
     1423u'' 
     1424>>> f.clean('http://www.google.com') # This will fail if there's no Internet connection 
     1425u'http://www.google.com' 
     1426 
     1427EmailField also access min_length and max_length parameters, for convenience. 
     1428>>> f = URLField(min_length=15, max_length=20) 
     1429>>> f.clean('http://f.com') 
     1430Traceback (most recent call last): 
     1431... 
     1432ValidationError: [u'Ensure this value has at least 15 characters.'] 
     1433>>> f.clean('http://example.com') 
     1434u'http://example.com' 
     1435>>> f.clean('http://abcdefghijklmnopqrstuvwxyz.com') 
     1436Traceback (most recent call last): 
     1437... 
     1438ValidationError: [u'Ensure this value has at most 20 characters.'] 
    11121439 
    11131440# BooleanField ################################################################ 
     
    11901517... 
    11911518ValidationError: [u'Select a valid choice. John is not one of the available choices.'] 
     1519 
     1520# NullBooleanField ############################################################ 
     1521 
     1522>>> f = NullBooleanField() 
     1523>>> f.clean('') 
     1524>>> f.clean(True) 
     1525True 
     1526>>> f.clean(False) 
     1527False 
     1528>>> f.clean(None) 
     1529>>> f.clean('1') 
     1530>>> f.clean('2') 
     1531>>> f.clean('3') 
     1532>>> f.clean('hello') 
    11921533 
    11931534# MultipleChoiceField ######################################################### 
     
    12971638u'' 
    12981639 
     1640# SplitDateTimeField ########################################################## 
     1641 
     1642>>> f = SplitDateTimeField() 
     1643>>> f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)]) 
     1644datetime.datetime(2006, 1, 10, 7, 30) 
     1645>>> f.clean(None) 
     1646Traceback (most recent call last): 
     1647... 
     1648ValidationError: [u'This field is required.'] 
     1649>>> f.clean('') 
     1650Traceback (most recent call last): 
     1651... 
     1652ValidationError: [u'This field is required.'] 
     1653>>> f.clean('hello') 
     1654Traceback (most recent call last): 
     1655... 
     1656ValidationError: [u'Enter a list of values.'] 
     1657>>> f.clean(['hello', 'there']) 
     1658Traceback (most recent call last): 
     1659... 
     1660ValidationError: [u'Enter a valid date.', u'Enter a valid time.'] 
     1661>>> f.clean(['2006-01-10', 'there']) 
     1662Traceback (most recent call last): 
     1663... 
     1664ValidationError: [u'Enter a valid time.'] 
     1665>>> f.clean(['hello', '07:30']) 
     1666Traceback (most recent call last): 
     1667... 
     1668ValidationError: [u'Enter a valid date.'] 
     1669 
     1670>>> f = SplitDateTimeField(required=False) 
     1671>>> f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)]) 
     1672datetime.datetime(2006, 1, 10, 7, 30) 
     1673>>> f.clean(None) 
     1674>>> f.clean('') 
     1675>>> f.clean('hello') 
     1676Traceback (most recent call last): 
     1677... 
     1678ValidationError: [u'Enter a list of values.'] 
     1679>>> f.clean(['hello', 'there']) 
     1680Traceback (most recent call last): 
     1681... 
     1682ValidationError: [u'Enter a valid date.', u'Enter a valid time.'] 
     1683>>> f.clean(['2006-01-10', 'there']) 
     1684Traceback (most recent call last): 
     1685... 
     1686ValidationError: [u'Enter a valid time.'] 
     1687>>> f.clean(['hello', '07:30']) 
     1688Traceback (most recent call last): 
     1689... 
     1690ValidationError: [u'Enter a valid date.'] 
     1691 
    12991692######### 
    13001693# Forms # 
     
    13141707Pass a dictionary to a Form's __init__(). 
    13151708>>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'}) 
     1709>>> p.is_bound 
     1710True 
    13161711>>> p.errors 
    13171712{} 
     
    13251720{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} 
    13261721>>> print p['first_name'] 
    1327 <input type="text" name="first_name" value="John" /> 
     1722<input type="text" name="first_name" value="John" id="id_first_name" /> 
    13281723>>> print p['last_name'] 
    1329 <input type="text" name="last_name" value="Lennon" /> 
     1724<input type="text" name="last_name" value="Lennon" id="id_last_name" /> 
    13301725>>> print p['birthday'] 
    1331 <input type="text" name="birthday" value="1940-10-9" /> 
     1726<input type="text" name="birthday" value="1940-10-9" id="id_birthday" /> 
     1727>>> print p['nonexistentfield'] 
     1728Traceback (most recent call last): 
     1729... 
     1730KeyError: "Key 'nonexistentfield' not found in Form" 
     1731 
    13321732>>> for boundfield in p: 
    13331733...     print boundfield 
    1334 <input type="text" name="first_name" value="John" /> 
    1335 <input type="text" name="last_name" value="Lennon" /> 
    1336 <input type="text" name="birthday" value="1940-10-9" /> 
     1734<input type="text" name="first_name" value="John" id="id_first_name" /> 
     1735<input type="text" name="last_name" value="Lennon" id="id_last_name" /> 
     1736<input type="text" name="birthday" value="1940-10-9" id="id_birthday" /> 
    13371737>>> for boundfield in p: 
    1338 ...     print boundfield.verbose_name, boundfield.data 
     1738...     print boundfield.label, boundfield.data 
    13391739First name John 
    13401740Last name Lennon 
    13411741Birthday 1940-10-9 
    13421742>>> print p 
    1343 <tr><td>First name:</td><td><input type="text" name="first_name" value="John" /></td></tr> 
    1344 <tr><td>Last name:</td><td><input type="text" name="last_name" value="Lennon" /></td></tr> 
    1345 <tr><td>Birthday:</td><td><input type="text" name="birthday" value="1940-10-9" /></td></tr> 
     1743<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" value="John" id="id_first_name" /></td></tr> 
     1744<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" value="Lennon" id="id_last_name" /></td></tr> 
     1745<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></td></tr> 
    13461746 
    13471747Empty dictionaries are valid, too. 
    13481748>>> p = Person({}) 
     1749>>> p.is_bound 
     1750True 
    13491751>>> p.errors 
    13501752{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']} 
    13511753>>> p.is_valid() 
    13521754False 
     1755>>> p.clean_data 
    &