Changeset 4455 for django/branches/sqlalchemy/tests
- Timestamp:
- 01/31/07 17:43:09 (2 years ago)
- Files:
-
- django/branches/sqlalchemy/tests/modeltests/basic/models.py (modified) (5 diffs)
- django/branches/sqlalchemy/tests/modeltests/custom_columns/models.py (modified) (2 diffs)
- django/branches/sqlalchemy/tests/modeltests/generic_relations/models.py (modified) (2 diffs)
- django/branches/sqlalchemy/tests/modeltests/get_object_or_404 (copied) (copied from django/trunk/tests/modeltests/get_object_or_404)
- django/branches/sqlalchemy/tests/modeltests/get_object_or_404/__init__.py (copied) (copied from django/trunk/tests/modeltests/get_object_or_404/__init__.py)
- django/branches/sqlalchemy/tests/modeltests/get_object_or_404/models.py (copied) (copied from django/trunk/tests/modeltests/get_object_or_404/models.py)
- django/branches/sqlalchemy/tests/modeltests/lookup/models.py (modified) (1 diff)
- django/branches/sqlalchemy/tests/modeltests/many_to_many/models.py (modified) (2 diffs)
- django/branches/sqlalchemy/tests/modeltests/model_forms (copied) (copied from django/trunk/tests/modeltests/model_forms)
- django/branches/sqlalchemy/tests/modeltests/model_forms/__init__.py (copied) (copied from django/trunk/tests/modeltests/model_forms/__init__.py)
- django/branches/sqlalchemy/tests/modeltests/model_forms/models.py (copied) (copied from django/trunk/tests/modeltests/model_forms/models.py)
- django/branches/sqlalchemy/tests/modeltests/or_lookups/models.py (modified) (1 diff)
- django/branches/sqlalchemy/tests/modeltests/serializers/models.py (modified) (2 diffs)
- django/branches/sqlalchemy/tests/modeltests/test_client/views.py (modified) (2 diffs)
- django/branches/sqlalchemy/tests/regressiontests/defaultfilters/tests.py (modified) (1 diff)
- django/branches/sqlalchemy/tests/regressiontests/forms/tests.py (modified) (55 diffs)
- django/branches/sqlalchemy/tests/regressiontests/invalid_admin_options (copied) (copied from django/trunk/tests/regressiontests/invalid_admin_options)
- django/branches/sqlalchemy/tests/regressiontests/invalid_admin_options/__init__.py (copied) (copied from django/trunk/tests/regressiontests/invalid_admin_options/__init__.py)
- django/branches/sqlalchemy/tests/regressiontests/invalid_admin_options/models.py (copied) (copied from django/trunk/tests/regressiontests/invalid_admin_options/models.py)
- django/branches/sqlalchemy/tests/runtests.py (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/sqlalchemy/tests/modeltests/basic/models.py
r3832 r4455 11 11 pub_date = models.DateTimeField() 12 12 13 class Meta: 14 ordering = ('pub_date','headline') 15 13 16 def __str__(self): 14 17 return self.headline … … 246 249 # Slices (without step) are lazy: 247 250 >>> 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>] 249 252 250 253 # Slicing again works: … … 254 257 [<Article: Area woman programs in Python>, <Article: Second article>] 255 258 >>> Article.objects.all()[0:5][4:] 256 [<Article: Article 6>]259 [<Article: Default headline>] 257 260 >>> Article.objects.all()[0:5][5:] 258 261 [] … … 260 263 # Some more tests! 261 264 >>> Article.objects.all()[2:][0:2] 262 [<Article: Third article>, <Article: Fourth article>]265 [<Article: Third article>, <Article: Article 6>] 263 266 >>> Article.objects.all()[2:][:2] 264 [<Article: Third article>, <Article: Fourth article>]267 [<Article: Third article>, <Article: Article 6>] 265 268 >>> Article.objects.all()[2:][2:3] 266 [<Article: Article 6>]269 [<Article: Default headline>] 267 270 268 271 # Note that you can't use 'offset' without 'limit' (on some dbs), so this doesn't work: … … 313 316 # Bulk delete test: How many objects before and after the delete? 314 317 >>> 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>] 316 319 >>> Article.objects.filter(id__lte=4).delete() 317 320 >>> Article.objects.all() django/branches/sqlalchemy/tests/modeltests/custom_columns/models.py
r3661 r4455 1 1 """ 2 17. Custom column names2 17. Custom column/table names 3 3 4 4 If your database column name is different than your model attribute, use the 5 5 ``db_column`` parameter. Note that you'll use the field's name, not its column 6 6 name, in API usage. 7 8 If 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 10 query the database. 11 12 If you need to use a table name for a many-to-many relationship that differs 13 from the default generated name, use the ``db_table`` parameter on the 14 ManyToMany field. This has no effect on the API for querying the database. 15 7 16 """ 8 17 9 18 from django.db import models 10 19 11 class Person(models.Model):20 class Author(models.Model): 12 21 first_name = models.CharField(maxlength=30, db_column='firstname') 13 22 last_name = models.CharField(maxlength=30, db_column='last') … … 16 25 return '%s %s' % (self.first_name, self.last_name) 17 26 27 class Meta: 28 db_table = 'my_author_table' 29 ordering = ('last_name','first_name') 30 31 class 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 18 41 __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() 22 45 23 >>> p.id46 >>> a.id 24 47 1 25 48 26 >>> Person.objects.all() 27 [<Person: John Smith>] 49 # Create another author 50 >>> a2 = Author(first_name='Peter', last_name='Jones') 51 >>> a2.save() 28 52 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] 31 57 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... 34 60 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') 36 72 Traceback (most recent call last): 37 73 ... 38 74 TypeError: Cannot resolve keyword 'firstname' into field 39 75 40 >>> p = Person.objects.get(last_name__exact='Smith')41 >>> p.first_name76 >>> a = Author.objects.get(last_name__exact='Smith') 77 >>> a.first_name 42 78 'John' 43 >>> p.last_name79 >>> a.last_name 44 80 'Smith' 45 >>> p.firstname81 >>> a.firstname 46 82 Traceback (most recent call last): 47 83 ... 48 AttributeError: ' Person' object has no attribute 'firstname'49 >>> p.last84 AttributeError: 'Author' object has no attribute 'firstname' 85 >>> a.last 50 86 Traceback (most recent call last): 51 87 ... 52 AttributeError: 'Person' object has no attribute 'last' 88 AttributeError: '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 53 105 """} django/branches/sqlalchemy/tests/modeltests/generic_relations/models.py
r3661 r4455 66 66 # Objects with declared GenericRelations can be tagged directly -- the API 67 67 # mimics the many-to-many API. 68 >>> bacon.tags.create(tag="fatty") 69 <TaggedItem: fatty> 70 >>> bacon.tags.create(tag="salty") 71 <TaggedItem: salty> 68 72 >>> lion.tags.create(tag="yellow") 69 73 <TaggedItem: yellow> 70 74 >>> lion.tags.create(tag="hairy") 71 75 <TaggedItem: hairy> 72 >>> bacon.tags.create(tag="fatty")73 <TaggedItem: fatty>74 >>> bacon.tags.create(tag="salty")75 <TaggedItem: salty>76 76 77 77 >>> lion.tags.all() … … 106 106 >>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id) 107 107 [<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 108 134 """} django/branches/sqlalchemy/tests/modeltests/lookup/models.py
r3661 r4455 192 192 [<Article: Article with \ backslash>] 193 193 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() 200 0 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 194 209 """} django/branches/sqlalchemy/tests/modeltests/many_to_many/models.py
r3661 r4455 204 204 [<Article: Oxygen-free diet works wonders>] 205 205 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. 207 219 >>> p1 = Publication(id=None, title='The Python Journal') 208 220 >>> p1.save() … … 232 244 [<Article: NASA uses Python>] 233 245 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 234 258 """} django/branches/sqlalchemy/tests/modeltests/or_lookups/models.py
r3661 r4455 70 70 [<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>] 71 71 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 72 87 # Q arg objects are ANDed 73 88 >>> Article.objects.filter(Q(headline__startswith='Hello'), Q(headline__contains='bye')) django/branches/sqlalchemy/tests/modeltests/serializers/models.py
r3661 r4455 37 37 def __str__(self): 38 38 return self.headline 39 40 class 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 39 46 40 47 __test__ = {'API_TESTS':""" … … 119 126 [<Article: Just kidding; I love TV poker>, <Article: Time to reform copyright>] 120 127 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 121 142 """} django/branches/sqlalchemy/tests/modeltests/test_client/views.py
r3724 r4455 27 27 return HttpResponseRedirect('/test_client/get_view/') 28 28 29 @login_required30 29 def login_protected_view(request): 31 30 "A simple view that is login protected." … … 34 33 35 34 return HttpResponse(t.render(c)) 35 login_protected_view = login_required(login_protected_view) django/branches/sqlalchemy/tests/regressiontests/defaultfilters/tests.py
r3832 r4455 12 12 >>> floatformat(0.0) 13 13 '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 '' 14 34 15 35 >>> addslashes('"double quotes" and \'single quotes\'') django/branches/sqlalchemy/tests/regressiontests/forms/tests.py
r4186 r4455 107 107 u'<input type="hidden" class="special" name="email" />' 108 108 109 # MultipleHiddenInput Widget ################################################## 110 111 >>> w = MultipleHiddenInput() 112 >>> w.render('email', []) 113 u'' 114 >>> w.render('email', None) 115 u'' 116 >>> w.render('email', ['test@example.com']) 117 u'<input type="hidden" name="email" value="test@example.com" />' 118 >>> w.render('email', ['some "quoted" & ampersanded value']) 119 u'<input type="hidden" name="email" value="some "quoted" & ampersanded value" />' 120 >>> w.render('email', ['test@example.com', 'foo@example.com']) 121 u'<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'}) 123 u'<input type="hidden" name="email" value="test@example.com" class="fun" />' 124 >>> w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'}) 125 u'<input type="hidden" name="email" value="test@example.com" class="fun" />\n<input type="hidden" name="email" value="foo@example.com" class="fun" />' 126 127 You can also pass 'attrs' to the constructor: 128 >>> w = MultipleHiddenInput(attrs={'class': 'fun'}) 129 >>> w.render('email', []) 130 u'' 131 >>> w.render('email', ['foo@example.com']) 132 u'<input type="hidden" class="fun" value="foo@example.com" name="email" />' 133 >>> w.render('email', ['foo@example.com', 'test@example.com']) 134 u'<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'}) 139 u'<input type="hidden" class="special" value="foo@example.com" name="email" />' 140 141 >>> w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'}) 142 u'<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'}) 147 u'<input type="hidden" class="special" value="foo@example.com" name="email" />' 148 109 149 # FileInput Widget ############################################################ 110 150 … … 296 336 >>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]) 297 337 u'<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 339 If choices is passed to the constructor and is a generator, it can be iterated 340 over 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> 298 392 299 393 # SelectMultiple Widget ####################################################### … … 515 609 beatle J R Ringo False 516 610 611 A RadioFieldRenderer object also allows index access to individual RadioInput 612 objects. 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() 620 True 621 >>> r[1].is_checked() 622 False 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] 626 Traceback (most recent call last): 627 ... 628 IndexError: list index out of range 629 630 >>> w = RadioSelect() 631 >>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])) 632 u'<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 517 634 # CheckboxSelectMultiple Widget ############################################### 518 635 … … 622 739 u'<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>' 623 740 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']) 752 u'<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') 754 u'<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', '') 760 u'<input type="text" name="date_0" /><input type="text" name="date_1" />' 761 >>> w.render('date', None) 762 u'<input type="text" name="date_0" /><input type="text" name="date_1" />' 763 >>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30)) 764 u'<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)]) 766 u'<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />' 767 768 You can also pass 'attrs' to the constructor. In this case, the attrs will be 769 included on both widgets. 770 >>> w = SplitDateTimeWidget(attrs={'class': 'pretty'}) 771 >>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30)) 772 u'<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 624 774 ########## 625 775 # Fields # … … 637 787 Widget that it'll use if you don't specify this. In most cases, 638 788 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. 639 794 640 795 Other than that, the Field subclasses have class-specific options for … … 685 840 >>> f = CharField(min_length=10, required=False) 686 841 >>> f.clean('') 842 u'' 843 >>> f.clean('12345') 687 844 Traceback (most recent call last): 688 845 ... 689 846 ValidationError: [u'Ensure this value has at least 10 characters.'] 847 >>> f.clean('1234567890') 848 u'1234567890' 849 >>> f.clean('1234567890a') 850 u'1234567890a' 851 852 >>> f = CharField(min_length=10, required=True) 853 >>> f.clean('') 854 Traceback (most recent call last): 855 ... 856 ValidationError: [u'This field is required.'] 690 857 >>> f.clean('12345') 691 858 Traceback (most recent call last): … … 731 898 >>> f = IntegerField(required=False) 732 899 >>> f.clean('') 733 u'' 900 >>> repr(f.clean('')) 901 'None' 734 902 >>> f.clean(None) 735 u'' 903 >>> repr(f.clean(None)) 904 'None' 736 905 >>> f.clean('1') 737 906 1 … … 754 923 ... 755 924 ValidationError: [u'Enter a whole number.'] 925 926 IntegerField accepts an optional max_value parameter: 927 >>> f = IntegerField(max_value=10) 928 >>> f.clean(None) 929 Traceback (most recent call last): 930 ... 931 ValidationError: [u'This field is required.'] 932 >>> f.clean(1) 933 1 934 >>> f.clean(10) 935 10 936 >>> f.clean(11) 937 Traceback (most recent call last): 938 ... 939 ValidationError: [u'Ensure this value is less than or equal to 10.'] 940 >>> f.clean('10') 941 10 942 >>> f.clean('11') 943 Traceback (most recent call last): 944 ... 945 ValidationError: [u'Ensure this value is less than or equal to 10.'] 946 947 IntegerField accepts an optional min_value parameter: 948 >>> f = IntegerField(min_value=10) 949 >>> f.clean(None) 950 Traceback (most recent call last): 951 ... 952 ValidationError: [u'This field is required.'] 953 >>> f.clean(1) 954 Traceback (most recent call last): 955 ... 956 ValidationError: [u'Ensure this value is greater than or equal to 10.'] 957 >>> f.clean(10) 958 10 959 >>> f.clean(11) 960 11 961 >>> f.clean('10') 962 10 963 >>> f.clean('11') 964 11 965 966 min_value and max_value can be used together: 967 >>> f = IntegerField(min_value=10, max_value=20) 968 >>> f.clean(None) 969 Traceback (most recent call last): 970 ... 971 ValidationError: [u'This field is required.'] 972 >>> f.clean(1) 973 Traceback (most recent call last): 974 ... 975 ValidationError: [u'Ensure this value is greater than or equal to 10.'] 976 >>> f.clean(10) 977 10 978 >>> f.clean(11) 979 11 980 >>> f.clean('10') 981 10 982 >>> f.clean('11') 983 11 984 >>> f.clean(20) 985 20 986 >>> f.clean(21) 987 Traceback (most recent call last): 988 ... 989 ValidationError: [u'Ensure this value is less than or equal to 20.'] 756 990 757 991 # DateField ################################################################### … … 831 1065 ... 832 1066 ValidationError: [u'Enter a valid date.'] 1067 1068 # TimeField ################################################################### 1069 1070 >>> import datetime 1071 >>> f = TimeField() 1072 >>> f.clean(datetime.time(14, 25)) 1073 datetime.time(14, 25) 1074 >>> f.clean(datetime.time(14, 25, 59)) 1075 datetime.time(14, 25, 59) 1076 >>> f.clean('14:25') 1077 datetime.time(14, 25) 1078 >>> f.clean('14:25:59') 1079 datetime.time(14, 25, 59) 1080 >>> f.clean('hello') 1081 Traceback (most recent call last): 1082 ... 1083 ValidationError: [u'Enter a valid time.'] 1084 >>> f.clean('1:24 p.m.') 1085 Traceback (most recent call last): 1086 ... 1087 ValidationError: [u'Enter a valid time.'] 1088 1089 TimeField accepts an optional input_formats parameter: 1090 >>> f = TimeField(input_formats=['%I:%M %p']) 1091 >>> f.clean(datetime.time(14, 25)) 1092 datetime.time(14, 25) 1093 >>> f.clean(datetime.time(14, 25, 59)) 1094 datetime.time(14, 25, 59) 1095 >>> f.clean('4:25 AM') 1096 datetime.time(4, 25) 1097 >>> f.clean('4:25 PM') 1098 datetime.time(16, 25) 1099 1100 The input_formats parameter overrides all default input formats, 1101 so the default formats won't work unless you specify them: 1102 >>> f.clean('14:30:45') 1103 Traceback (most recent call last): 1104 ... 1105 ValidationError: [u'Enter a valid time.'] 833 1106 834 1107 # DateTimeField ############################################################### … … 961 1234 962 1235 RegexField 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.') 964 1237 >>> f.clean('1234') 965 1238 u'1234' … … 972 1245 ... 973 1246 ValidationError: [u'Enter a four-digit number.'] 1247 1248 RegexField also access min_length and max_length parameters, for convenience. 1249 >>> f = RegexField('^\d+$', min_length=5, max_length=10) 1250 >>> f.clean('123') 1251 Traceback (most recent call last): 1252 ... 1253 ValidationError: [u'Ensure this value has at least 5 characters.'] 1254 >>> f.clean('abc') 1255 Traceback (most recent call last): 1256 ... 1257 ValidationError: [u'Ensure this value has at least 5 characters.'] 1258 >>> f.clean('12345') 1259 u'12345' 1260 >>> f.clean('1234567890') 1261 u'1234567890' 1262 >>> f.clean('12345678901') 1263 Traceback (most recent call last): 1264 ... 1265 ValidationError: [u'Ensure this value has at most 10 characters.'] 1266 >>> f.clean('12345a') 1267 Traceback (most recent call last): 1268 ... 1269 ValidationError: [u'Enter a valid value.'] 974 1270 975 1271 # EmailField ################################################################## … … 1018 1314 ... 1019 1315 ValidationError: [u'Enter a valid e-mail address.'] 1316 1317 EmailField 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') 1320 Traceback (most recent call last): 1321 ... 1322 ValidationError: [u'Ensure this value has at least 10 characters.'] 1323 >>> f.clean('alf@foo.com') 1324 u'alf@foo.com' 1325 >>> f.clean('alf123456788@foo.com') 1326 Traceback (most recent call last): 1327 ... 1328 ValidationError: [u'Ensure this value has at most 15 characters.'] 1020 1329 1021 1330 # URLField ################################################################## … … 1110 1419 ... 1111 1420 ValidationError: [u'This URL appears to be a broken link.'] 1421 >>> f = URLField(verify_exists=True, required=False) 1422 >>> f.clean('') 1423 u'' 1424 >>> f.clean('http://www.google.com') # This will fail if there's no Internet connection 1425 u'http://www.google.com' 1426 1427 EmailField 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') 1430 Traceback (most recent call last): 1431 ... 1432 ValidationError: [u'Ensure this value has at least 15 characters.'] 1433 >>> f.clean('http://example.com') 1434 u'http://example.com' 1435 >>> f.clean('http://abcdefghijklmnopqrstuvwxyz.com') 1436 Traceback (most recent call last): 1437 ... 1438 ValidationError: [u'Ensure this value has at most 20 characters.'] 1112 1439 1113 1440 # BooleanField ################################################################ … … 1190 1517 ... 1191 1518 ValidationError: [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) 1525 True 1526 >>> f.clean(False) 1527 False 1528 >>> f.clean(None) 1529 >>> f.clean('1') 1530 >>> f.clean('2') 1531 >>> f.clean('3') 1532 >>> f.clean('hello') 1192 1533 1193 1534 # MultipleChoiceField ######################################################### … … 1297 1638 u'' 1298 1639 1640 # SplitDateTimeField ########################################################## 1641 1642 >>> f = SplitDateTimeField() 1643 >>> f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)]) 1644 datetime.datetime(2006, 1, 10, 7, 30) 1645 >>> f.clean(None) 1646 Traceback (most recent call last): 1647 ... 1648 ValidationError: [u'This field is required.'] 1649 >>> f.clean('') 1650 Traceback (most recent call last): 1651 ... 1652 ValidationError: [u'This field is required.'] 1653 >>> f.clean('hello') 1654 Traceback (most recent call last): 1655 ... 1656 ValidationError: [u'Enter a list of values.'] 1657 >>> f.clean(['hello', 'there']) 1658 Traceback (most recent call last): 1659 ... 1660 ValidationError: [u'Enter a valid date.', u'Enter a valid time.'] 1661 >>> f.clean(['2006-01-10', 'there']) 1662 Traceback (most recent call last): 1663 ... 1664 ValidationError: [u'Enter a valid time.'] 1665 >>> f.clean(['hello', '07:30']) 1666 Traceback (most recent call last): 1667 ... 1668 ValidationError: [u'Enter a valid date.'] 1669 1670 >>> f = SplitDateTimeField(required=False) 1671 >>> f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)]) 1672 datetime.datetime(2006, 1, 10, 7, 30) 1673 >>> f.clean(None) 1674 >>> f.clean('') 1675 >>> f.clean('hello') 1676 Traceback (most recent call last): 1677 ... 1678 ValidationError: [u'Enter a list of values.'] 1679 >>> f.clean(['hello', 'there']) 1680 Traceback (most recent call last): 1681 ... 1682 ValidationError: [u'Enter a valid date.', u'Enter a valid time.'] 1683 >>> f.clean(['2006-01-10', 'there']) 1684 Traceback (most recent call last): 1685 ... 1686 ValidationError: [u'Enter a valid time.'] 1687 >>> f.clean(['hello', '07:30']) 1688 Traceback (most recent call last): 1689 ... 1690 ValidationError: [u'Enter a valid date.'] 1691 1299 1692 ######### 1300 1693 # Forms # … … 1314 1707 Pass a dictionary to a Form's __init__(). 1315 1708 >>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'}) 1709 >>> p.is_bound 1710 True 1316 1711 >>> p.errors 1317 1712 {} … … 1325 1720 {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} 1326 1721 >>> 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" /> 1328 1723 >>> 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" /> 1330 1725 >>> 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'] 1728 Traceback (most recent call last): 1729 ... 1730 KeyError: "Key 'nonexistentfield' not found in Form" 1731 1332 1732 >>> for boundfield in p: 1333 1733 ... 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" /> 1337 1737 >>> for boundfield in p: 1338 ... print boundfield. verbose_name, boundfield.data1738 ... print boundfield.label, boundfield.data 1339 1739 First name John 1340 1740 Last name Lennon 1341 1741 Birthday 1940-10-9 1342 1742 >>> print p 1343 <tr><t d>First name:</td><td><input type="text" name="first_name" value="John" /></td></tr>1344 <tr><t d>Last name:</td><td><input type="text" name="last_name" value="Lennon" /></td></tr>1345 <tr><t d>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> 1346 1746 1347 1747 Empty dictionaries are valid, too. 1348 1748 >>> p = Person({}) 1749 >>> p.is_bound 1750 True 1349 1751 >>> p.errors 1350 1752 {'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']} 1351 1753 >>> p.is_valid() 1352 1754 False 1755 >>> p.clean_data &
