2013-07-30 01:19:04 +08:00
from __future__ import unicode_literals
2011-06-10 22:49:44 +08:00
2010-03-17 03:32:11 +08:00
import datetime
2011-06-10 22:08:51 +08:00
import os
from decimal import Decimal
2013-07-01 20:22:27 +08:00
from unittest import skipUnless
2013-02-22 05:56:55 +08:00
import warnings
2011-06-10 22:08:51 +08:00
2010-02-23 07:06:09 +08:00
from django import forms
2014-02-04 02:31:27 +08:00
from django . core . exceptions import FieldError , NON_FIELD_ERRORS
2011-06-10 22:08:51 +08:00
from django . core . files . uploadedfile import SimpleUploadedFile
from django . core . validators import ValidationError
2011-10-01 05:40:56 +08:00
from django . db import connection
2012-10-04 00:50:12 +08:00
from django . db . models . query import EmptyQuerySet
2011-06-10 22:08:51 +08:00
from django . forms . models import model_to_dict
2012-12-08 18:13:52 +08:00
from django . utils . _os import upath
2014-01-08 22:53:40 +08:00
from django . test import TestCase , skipUnlessDBFeature
2012-07-20 20:48:51 +08:00
from django . utils import six
2011-06-10 22:08:51 +08:00
2013-06-10 18:22:40 +08:00
from . models import ( Article , ArticleStatus , BetterWriter , BigInt , Book ,
2011-10-14 02:04:12 +08:00
Category , CommaSeparatedInteger , CustomFieldForExclusionModel , DerivedBook ,
DerivedPost , ExplicitPK , FlexibleDatePost , ImprovedArticle ,
2012-12-09 03:58:59 +08:00
ImprovedArticleWithParentLink , Inventory , Post , Price ,
2013-06-10 18:22:40 +08:00
Product , TextFile , Writer , WriterProfile , Colour , ColourfulItem ,
2014-02-02 03:23:31 +08:00
ArticleStatusNote , DateTimePost , CustomErrorMessage , test_images ,
StumpJoke , Character )
2011-06-10 22:08:51 +08:00
2011-06-13 21:23:49 +08:00
if test_images :
2011-10-14 02:04:12 +08:00
from . models import ImageFile , OptionalImageFile
2013-10-22 18:21:07 +08:00
2011-06-13 21:23:49 +08:00
class ImageFileForm ( forms . ModelForm ) :
class Meta :
model = ImageFile
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-13 21:23:49 +08:00
class OptionalImageFileForm ( forms . ModelForm ) :
class Meta :
model = OptionalImageFile
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class ProductForm ( forms . ModelForm ) :
class Meta :
model = Product
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class PriceForm ( forms . ModelForm ) :
class Meta :
model = Price
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class BookForm ( forms . ModelForm ) :
class Meta :
2013-06-14 22:02:30 +08:00
model = Book
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class DerivedBookForm ( forms . ModelForm ) :
class Meta :
model = DerivedBook
2013-06-14 22:02:30 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class ExplicitPKForm ( forms . ModelForm ) :
class Meta :
model = ExplicitPK
fields = ( ' key ' , ' desc ' , )
class PostForm ( forms . ModelForm ) :
class Meta :
model = Post
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
2013-05-28 21:56:14 +08:00
class DateTimePostForm ( forms . ModelForm ) :
class Meta :
model = DateTimePost
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class DerivedPostForm ( forms . ModelForm ) :
class Meta :
model = DerivedPost
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
2013-06-10 18:22:40 +08:00
class CustomWriterForm ( forms . ModelForm ) :
2013-09-04 02:22:21 +08:00
name = forms . CharField ( required = False )
2011-06-10 22:08:51 +08:00
2013-09-04 02:22:21 +08:00
class Meta :
model = Writer
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class FlexDatePostForm ( forms . ModelForm ) :
class Meta :
model = FlexibleDatePost
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class BaseCategoryForm ( forms . ModelForm ) :
class Meta :
model = Category
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class ArticleForm ( forms . ModelForm ) :
class Meta :
model = Article
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class PartialArticleForm ( forms . ModelForm ) :
class Meta :
model = Article
2013-10-27 03:15:03 +08:00
fields = ( ' headline ' , ' pub_date ' )
2011-06-10 22:08:51 +08:00
2013-02-22 05:56:55 +08:00
2011-06-10 22:08:51 +08:00
class RoykoForm ( forms . ModelForm ) :
class Meta :
2013-06-10 18:22:40 +08:00
model = Writer
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class TestArticleForm ( forms . ModelForm ) :
class Meta :
model = Article
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class PartialArticleFormWithSlug ( forms . ModelForm ) :
class Meta :
model = Article
2013-02-22 05:56:55 +08:00
fields = ( ' headline ' , ' slug ' , ' pub_date ' )
2011-06-10 22:08:51 +08:00
class ArticleStatusForm ( forms . ModelForm ) :
class Meta :
model = ArticleStatus
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class InventoryForm ( forms . ModelForm ) :
class Meta :
model = Inventory
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class SelectInventoryForm ( forms . Form ) :
items = forms . ModelMultipleChoiceField ( Inventory . objects . all ( ) , to_field_name = ' barcode ' )
2013-02-22 05:56:55 +08:00
2011-06-10 22:08:51 +08:00
class CustomFieldForExclusionForm ( forms . ModelForm ) :
class Meta :
model = CustomFieldForExclusionModel
fields = [ ' name ' , ' markup ' ]
2013-02-22 05:56:55 +08:00
2011-06-10 22:08:51 +08:00
class ShortCategory ( forms . ModelForm ) :
name = forms . CharField ( max_length = 5 )
slug = forms . CharField ( max_length = 5 )
url = forms . CharField ( max_length = 3 )
2013-02-24 01:29:56 +08:00
class Meta :
model = Category
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2013-02-24 01:29:56 +08:00
2011-06-10 22:08:51 +08:00
class ImprovedArticleForm ( forms . ModelForm ) :
class Meta :
model = ImprovedArticle
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class ImprovedArticleWithParentLinkForm ( forms . ModelForm ) :
class Meta :
model = ImprovedArticleWithParentLink
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
2013-06-10 18:22:40 +08:00
class BetterWriterForm ( forms . ModelForm ) :
2011-06-10 22:08:51 +08:00
class Meta :
2013-06-10 18:22:40 +08:00
model = BetterWriter
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2013-11-03 06:50:35 +08:00
2013-06-10 18:22:40 +08:00
class WriterProfileForm ( forms . ModelForm ) :
2011-06-10 22:08:51 +08:00
class Meta :
2013-06-10 18:22:40 +08:00
model = WriterProfile
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class TextFileForm ( forms . ModelForm ) :
class Meta :
model = TextFile
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class BigIntForm ( forms . ModelForm ) :
class Meta :
model = BigInt
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class ModelFormWithMedia ( forms . ModelForm ) :
class Media :
js = ( ' /some/form/javascript ' , )
css = {
' all ' : ( ' /some/form/css ' , )
}
2013-10-22 18:21:07 +08:00
2011-06-10 22:08:51 +08:00
class Meta :
2012-12-09 03:58:59 +08:00
model = TextFile
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class CommaSeparatedIntegerForm ( forms . ModelForm ) :
2013-02-22 05:56:55 +08:00
class Meta :
model = CommaSeparatedInteger
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class PriceFormWithoutQuantity ( forms . ModelForm ) :
class Meta :
model = Price
exclude = ( ' quantity ' , )
2013-02-22 05:56:55 +08:00
2012-12-20 02:12:08 +08:00
class ColourfulItemForm ( forms . ModelForm ) :
class Meta :
model = ColourfulItem
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2012-12-20 02:12:08 +08:00
2013-05-22 05:32:39 +08:00
# model forms for testing work on #9321:
2013-11-03 06:50:35 +08:00
2013-05-22 05:32:39 +08:00
class StatusNoteForm ( forms . ModelForm ) :
class Meta :
model = ArticleStatusNote
fields = ' __all__ '
class StatusNoteCBM2mForm ( forms . ModelForm ) :
class Meta :
model = ArticleStatusNote
fields = ' __all__ '
widgets = { ' status ' : forms . CheckboxSelectMultiple }
2013-07-01 21:36:31 +08:00
2013-06-06 02:55:05 +08:00
class CustomErrorMessageForm ( forms . ModelForm ) :
name1 = forms . CharField ( error_messages = { ' invalid ' : ' Form custom error message. ' } )
class Meta :
2013-07-01 21:36:31 +08:00
fields = ' __all__ '
2013-06-06 02:55:05 +08:00
model = CustomErrorMessage
2011-06-10 22:08:51 +08:00
class ModelFormBaseTest ( TestCase ) :
def test_base_form ( self ) :
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( BaseCategoryForm . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' name ' , ' slug ' , ' url ' ] )
2013-02-22 05:56:55 +08:00
def test_missing_fields_attribute ( self ) :
2013-10-19 20:31:38 +08:00
with warnings . catch_warnings ( record = True ) :
2013-06-30 00:34:41 +08:00
warnings . simplefilter ( " always " , DeprecationWarning )
2013-02-22 05:56:55 +08:00
class MissingFieldsForm ( forms . ModelForm ) :
class Meta :
model = Category
# There is some internal state in warnings module which means that
# if a warning has been seen already, the catch_warnings won't
# have recorded it. The following line therefore will not work reliably:
2013-06-30 00:34:41 +08:00
# self.assertEqual(w[0].category, DeprecationWarning)
2013-02-22 05:56:55 +08:00
# Until end of the deprecation cycle, should still create the
# form as before:
self . assertEqual ( list ( MissingFieldsForm . base_fields ) ,
[ ' name ' , ' slug ' , ' url ' ] )
2011-06-10 22:08:51 +08:00
def test_extra_fields ( self ) :
class ExtraFields ( BaseCategoryForm ) :
some_extra_field = forms . BooleanField ( )
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( ExtraFields . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' name ' , ' slug ' , ' url ' , ' some_extra_field ' ] )
def test_replace_field ( self ) :
class ReplaceField ( forms . ModelForm ) :
url = forms . BooleanField ( )
class Meta :
model = Category
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2013-05-21 17:42:15 +08:00
self . assertIsInstance ( ReplaceField . base_fields [ ' url ' ] ,
2013-11-03 06:50:35 +08:00
forms . fields . BooleanField )
2013-02-22 05:56:55 +08:00
def test_replace_field_variant_2 ( self ) :
# Should have the same result as before,
# but 'fields' attribute specified differently
class ReplaceField ( forms . ModelForm ) :
url = forms . BooleanField ( )
class Meta :
model = Category
fields = [ ' url ' ]
2013-05-21 17:42:15 +08:00
self . assertIsInstance ( ReplaceField . base_fields [ ' url ' ] ,
2013-11-03 06:50:35 +08:00
forms . fields . BooleanField )
2013-02-22 05:56:55 +08:00
def test_replace_field_variant_3 ( self ) :
# Should have the same result as before,
# but 'fields' attribute specified differently
class ReplaceField ( forms . ModelForm ) :
url = forms . BooleanField ( )
class Meta :
model = Category
2013-11-03 05:02:56 +08:00
fields = [ ] # url will still appear, since it is explicit above
2011-06-10 22:08:51 +08:00
2013-05-21 17:42:15 +08:00
self . assertIsInstance ( ReplaceField . base_fields [ ' url ' ] ,
2013-11-03 06:50:35 +08:00
forms . fields . BooleanField )
2011-06-10 22:08:51 +08:00
def test_override_field ( self ) :
2013-06-10 18:22:40 +08:00
class WriterForm ( forms . ModelForm ) :
2011-06-10 22:08:51 +08:00
book = forms . CharField ( required = False )
class Meta :
2013-06-10 18:22:40 +08:00
model = Writer
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
2013-06-10 18:22:40 +08:00
wf = WriterForm ( { ' name ' : ' Richard Lockridge ' } )
2011-06-10 22:08:51 +08:00
self . assertTrue ( wf . is_valid ( ) )
2013-04-08 00:41:35 +08:00
def test_limit_nonexistent_field ( self ) :
expected_msg = ' Unknown field(s) (nonexistent) specified for Category '
with self . assertRaisesMessage ( FieldError , expected_msg ) :
class InvalidCategoryForm ( forms . ModelForm ) :
class Meta :
model = Category
fields = [ ' nonexistent ' ]
def test_limit_fields_with_string ( self ) :
expected_msg = " CategoryForm.Meta.fields cannot be a string. Did you mean to type: ( ' url ' ,)? "
with self . assertRaisesMessage ( TypeError , expected_msg ) :
class CategoryForm ( forms . ModelForm ) :
class Meta :
model = Category
2013-11-03 05:02:56 +08:00
fields = ( ' url ' ) # note the missing comma
2013-04-08 00:41:35 +08:00
2011-06-10 22:08:51 +08:00
def test_exclude_fields ( self ) :
class ExcludeFields ( forms . ModelForm ) :
class Meta :
model = Category
exclude = [ ' url ' ]
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( ExcludeFields . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' name ' , ' slug ' ] )
2013-04-08 00:41:35 +08:00
def test_exclude_nonexistent_field ( self ) :
class ExcludeFields ( forms . ModelForm ) :
class Meta :
model = Category
exclude = [ ' nonexistent ' ]
self . assertEqual ( list ( ExcludeFields . base_fields ) ,
[ ' name ' , ' slug ' , ' url ' ] )
def test_exclude_fields_with_string ( self ) :
expected_msg = " CategoryForm.Meta.exclude cannot be a string. Did you mean to type: ( ' url ' ,)? "
with self . assertRaisesMessage ( TypeError , expected_msg ) :
class CategoryForm ( forms . ModelForm ) :
class Meta :
model = Category
2013-11-03 05:02:56 +08:00
exclude = ( ' url ' ) # note the missing comma
2013-04-08 00:41:35 +08:00
2011-06-10 22:08:51 +08:00
def test_confused_form ( self ) :
class ConfusedForm ( forms . ModelForm ) :
""" Using ' fields ' *and* ' exclude ' . Not sure why you ' d want to do
this , but uh , " be liberal in what you accept " and all .
"""
class Meta :
model = Category
fields = [ ' name ' , ' url ' ]
exclude = [ ' url ' ]
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( ConfusedForm . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' name ' ] )
def test_mixmodel_form ( self ) :
class MixModelForm ( BaseCategoryForm ) :
""" Don ' t allow more than one ' model ' definition in the
inheritance hierarchy . Technically , it would generate a valid
form , but the fact that the resulting save method won ' t deal with
multiple objects is likely to trip up people not familiar with the
mechanics .
"""
class Meta :
model = Article
2013-02-22 05:56:55 +08:00
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
# MixModelForm is now an Article-related thing, because MixModelForm.Meta
# overrides BaseCategoryForm.Meta.
self . assertEqual (
2012-08-15 05:38:35 +08:00
list ( MixModelForm . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' headline ' , ' slug ' , ' pub_date ' , ' writer ' , ' article ' , ' categories ' , ' status ' ]
)
def test_article_form ( self ) :
self . assertEqual (
2012-08-15 05:38:35 +08:00
list ( ArticleForm . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' headline ' , ' slug ' , ' pub_date ' , ' writer ' , ' article ' , ' categories ' , ' status ' ]
)
def test_bad_form ( self ) :
2013-11-03 05:02:56 +08:00
# First class with a Meta class wins...
2011-06-10 22:08:51 +08:00
class BadForm ( ArticleForm , BaseCategoryForm ) :
pass
self . assertEqual (
2012-08-15 05:38:35 +08:00
list ( BadForm . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' headline ' , ' slug ' , ' pub_date ' , ' writer ' , ' article ' , ' categories ' , ' status ' ]
)
2013-02-24 01:29:56 +08:00
def test_invalid_meta_model ( self ) :
class InvalidModelForm ( forms . ModelForm ) :
class Meta :
pass # no model
# Can't create new form
with self . assertRaises ( ValueError ) :
2013-10-19 20:31:38 +08:00
InvalidModelForm ( )
2013-02-24 01:29:56 +08:00
# Even if you provide a model instance
with self . assertRaises ( ValueError ) :
2013-10-19 20:31:38 +08:00
InvalidModelForm ( instance = Category )
2013-02-24 01:29:56 +08:00
2011-06-10 22:08:51 +08:00
def test_subcategory_form ( self ) :
class SubCategoryForm ( BaseCategoryForm ) :
""" Subclassing without specifying a Meta on the class will use
the parent ' s Meta (or the first parent in the MRO if there are
multiple parent classes ) .
"""
pass
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( SubCategoryForm . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' name ' , ' slug ' , ' url ' ] )
def test_subclassmeta_form ( self ) :
class SomeCategoryForm ( forms . ModelForm ) :
2013-09-04 02:22:21 +08:00
checkbox = forms . BooleanField ( )
2011-06-10 22:08:51 +08:00
2013-09-04 02:22:21 +08:00
class Meta :
model = Category
fields = ' __all__ '
2011-06-10 22:08:51 +08:00
class SubclassMeta ( SomeCategoryForm ) :
""" We can also subclass the Meta inner class to change the fields
list .
"""
class Meta ( SomeCategoryForm . Meta ) :
exclude = [ ' url ' ]
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2011-06-10 22:08:51 +08:00
str ( SubclassMeta ( ) ) ,
""" <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_slug " > Slug : < / label > < / th > < td > < input id = " id_slug " type = " text " name = " slug " maxlength = " 20 " / > < / td > < / tr >
< tr > < th > < label for = " id_checkbox " > Checkbox : < / label > < / th > < td > < input type = " checkbox " name = " checkbox " id = " id_checkbox " / > < / td > < / tr > """
2013-10-18 17:02:43 +08:00
)
2011-06-10 22:08:51 +08:00
def test_orderfields_form ( self ) :
class OrderFields ( forms . ModelForm ) :
class Meta :
model = Category
fields = [ ' url ' , ' name ' ]
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( OrderFields . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' url ' , ' name ' ] )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2011-06-10 22:08:51 +08:00
str ( OrderFields ( ) ) ,
""" <tr><th><label for= " id_url " >The URL:</label></th><td><input id= " id_url " type= " text " name= " url " maxlength= " 40 " /></td></tr>
< tr > < th > < label for = " id_name " > Name : < / label > < / th > < td > < input id = " id_name " type = " text " name = " name " maxlength = " 20 " / > < / td > < / tr > """
2013-10-18 17:02:43 +08:00
)
2011-06-10 22:08:51 +08:00
def test_orderfields2_form ( self ) :
class OrderFields2 ( forms . ModelForm ) :
class Meta :
model = Category
fields = [ ' slug ' , ' url ' , ' name ' ]
exclude = [ ' url ' ]
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( OrderFields2 . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' slug ' , ' name ' ] )
2013-04-04 03:51:37 +08:00
class FieldOverridesTroughFormMetaForm ( forms . ModelForm ) :
2011-06-10 22:08:51 +08:00
class Meta :
model = Category
fields = [ ' name ' , ' url ' , ' slug ' ]
widgets = {
' name ' : forms . Textarea ,
' url ' : forms . TextInput ( attrs = { ' class ' : ' url ' } )
}
2013-04-04 03:51:37 +08:00
labels = {
' name ' : ' Title ' ,
}
help_texts = {
' slug ' : ' Watch out! Letters, numbers, underscores and hyphens only. ' ,
}
error_messages = {
' slug ' : {
' invalid ' : (
" Didn ' t you read the help text? "
" We said letters, numbers, underscores and hyphens only! "
)
}
}
2011-06-10 22:08:51 +08:00
2014-02-02 03:23:31 +08:00
class StumpJokeForm ( forms . ModelForm ) :
class Meta :
model = StumpJoke
fields = ' __all__ '
2013-04-04 03:51:37 +08:00
class TestFieldOverridesTroughFormMeta ( TestCase ) :
def test_widget_overrides ( self ) :
form = FieldOverridesTroughFormMetaForm ( )
self . assertHTMLEqual (
str ( form [ ' name ' ] ) ,
' <textarea id= " id_name " rows= " 10 " cols= " 40 " name= " name " ></textarea> ' ,
)
self . assertHTMLEqual (
str ( form [ ' url ' ] ) ,
' <input id= " id_url " type= " text " class= " url " name= " url " maxlength= " 40 " /> ' ,
)
self . assertHTMLEqual (
str ( form [ ' slug ' ] ) ,
' <input id= " id_slug " type= " text " name= " slug " maxlength= " 20 " /> ' ,
)
2011-06-10 22:08:51 +08:00
2013-04-04 03:51:37 +08:00
def test_label_overrides ( self ) :
form = FieldOverridesTroughFormMetaForm ( )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2013-04-04 03:51:37 +08:00
str ( form [ ' name ' ] . label_tag ( ) ) ,
' <label for= " id_name " >Title:</label> ' ,
2011-06-10 22:08:51 +08:00
)
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2013-04-04 03:51:37 +08:00
str ( form [ ' url ' ] . label_tag ( ) ) ,
' <label for= " id_url " >The URL:</label> ' ,
2011-06-10 22:08:51 +08:00
)
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2013-04-04 03:51:37 +08:00
str ( form [ ' slug ' ] . label_tag ( ) ) ,
' <label for= " id_slug " >Slug:</label> ' ,
)
def test_help_text_overrides ( self ) :
form = FieldOverridesTroughFormMetaForm ( )
self . assertEqual (
form [ ' slug ' ] . help_text ,
' Watch out! Letters, numbers, underscores and hyphens only. ' ,
2011-06-10 22:08:51 +08:00
)
2010-02-23 07:06:09 +08:00
2013-04-04 03:51:37 +08:00
def test_error_messages_overrides ( self ) :
form = FieldOverridesTroughFormMetaForm ( data = {
' name ' : ' Category ' ,
' url ' : ' /category/ ' ,
' slug ' : ' ! % #*@ ' ,
} )
form . full_clean ( )
error = [
" Didn ' t you read the help text? "
" We said letters, numbers, underscores and hyphens only! " ,
]
self . assertEqual ( form . errors , { ' slug ' : error } )
2010-02-23 07:06:09 +08:00
2010-02-26 01:18:27 +08:00
class IncompleteCategoryFormWithFields ( forms . ModelForm ) :
2010-02-23 07:06:09 +08:00
"""
A form that replaces the model ' s url field with a custom one. This should
prevent the model field ' s validation from being called.
"""
url = forms . CharField ( required = False )
class Meta :
fields = ( ' name ' , ' slug ' )
model = Category
2013-11-03 06:50:35 +08:00
2010-02-26 01:18:27 +08:00
class IncompleteCategoryFormWithExclude ( forms . ModelForm ) :
"""
A form that replaces the model ' s url field with a custom one. This should
prevent the model field ' s validation from being called.
"""
url = forms . CharField ( required = False )
class Meta :
exclude = [ ' url ' ]
model = Category
2010-02-23 07:06:09 +08:00
class ValidationTest ( TestCase ) :
2010-02-26 01:18:27 +08:00
def test_validates_with_replaced_field_not_specified ( self ) :
form = IncompleteCategoryFormWithFields ( data = { ' name ' : ' some name ' , ' slug ' : ' some-slug ' } )
assert form . is_valid ( )
def test_validates_with_replaced_field_excluded ( self ) :
form = IncompleteCategoryFormWithExclude ( data = { ' name ' : ' some name ' , ' slug ' : ' some-slug ' } )
2010-02-23 07:06:09 +08:00
assert form . is_valid ( )
2010-03-18 10:03:07 +08:00
def test_notrequired_overrides_notblank ( self ) :
2013-06-10 18:22:40 +08:00
form = CustomWriterForm ( { } )
2010-03-18 10:03:07 +08:00
assert form . is_valid ( )
2011-06-10 22:08:51 +08:00
2010-03-17 03:32:11 +08:00
# unique/unique_together validation
class UniqueTest ( TestCase ) :
def setUp ( self ) :
2013-06-10 18:22:40 +08:00
self . writer = Writer . objects . create ( name = ' Mike Royko ' )
2010-03-17 03:32:11 +08:00
def test_simple_unique ( self ) :
form = ProductForm ( { ' slug ' : ' teddy-bear-blue ' } )
self . assertTrue ( form . is_valid ( ) )
obj = form . save ( )
form = ProductForm ( { ' slug ' : ' teddy-bear-blue ' } )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' slug ' ] , [ ' Product with this Slug already exists. ' ] )
2010-03-17 03:32:11 +08:00
form = ProductForm ( { ' slug ' : ' teddy-bear-blue ' } , instance = obj )
self . assertTrue ( form . is_valid ( ) )
def test_unique_together ( self ) :
""" ModelForm test of unique_together constraint """
form = PriceForm ( { ' price ' : ' 6.00 ' , ' quantity ' : ' 1 ' } )
self . assertTrue ( form . is_valid ( ) )
form . save ( )
form = PriceForm ( { ' price ' : ' 6.00 ' , ' quantity ' : ' 1 ' } )
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' __all__ ' ] , [ ' Price with this Price and Quantity already exists. ' ] )
2010-03-17 03:32:11 +08:00
2014-01-08 22:53:40 +08:00
@skipUnlessDBFeature ( ' ignores_nulls_in_unique_constraints ' )
2010-03-17 03:32:11 +08:00
def test_unique_null ( self ) :
title = ' I May Be Wrong But I Doubt It '
2013-06-10 18:22:40 +08:00
form = BookForm ( { ' title ' : title , ' author ' : self . writer . pk } )
2010-03-17 03:32:11 +08:00
self . assertTrue ( form . is_valid ( ) )
form . save ( )
2013-06-10 18:22:40 +08:00
form = BookForm ( { ' title ' : title , ' author ' : self . writer . pk } )
2010-03-17 03:32:11 +08:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' __all__ ' ] , [ ' Book with this Title and Author already exists. ' ] )
2013-06-10 18:22:40 +08:00
form = BookForm ( { ' title ' : title } )
2010-03-17 03:32:11 +08:00
self . assertTrue ( form . is_valid ( ) )
form . save ( )
2013-06-10 18:22:40 +08:00
form = BookForm ( { ' title ' : title } )
2010-03-17 03:32:11 +08:00
self . assertTrue ( form . is_valid ( ) )
def test_inherited_unique ( self ) :
2013-06-10 18:22:40 +08:00
title = ' Boss '
Book . objects . create ( title = title , author = self . writer , special_id = 1 )
form = DerivedBookForm ( { ' title ' : ' Other ' , ' author ' : self . writer . pk , ' special_id ' : ' 1 ' , ' isbn ' : ' 12345 ' } )
2010-03-17 03:32:11 +08:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2013-06-10 18:22:40 +08:00
self . assertEqual ( form . errors [ ' special_id ' ] , [ ' Book with this Special id already exists. ' ] )
2010-03-17 03:32:11 +08:00
def test_inherited_unique_together ( self ) :
title = ' Boss '
2013-06-10 18:22:40 +08:00
form = BookForm ( { ' title ' : title , ' author ' : self . writer . pk } )
2010-03-17 03:32:11 +08:00
self . assertTrue ( form . is_valid ( ) )
form . save ( )
2013-06-10 18:22:40 +08:00
form = DerivedBookForm ( { ' title ' : title , ' author ' : self . writer . pk , ' isbn ' : ' 12345 ' } )
2010-03-17 03:32:11 +08:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' __all__ ' ] , [ ' Book with this Title and Author already exists. ' ] )
2010-03-17 03:32:11 +08:00
def test_abstract_inherited_unique ( self ) :
title = ' Boss '
isbn = ' 12345 '
2013-10-19 20:31:38 +08:00
DerivedBook . objects . create ( title = title , author = self . writer , isbn = isbn )
2013-06-10 18:22:40 +08:00
form = DerivedBookForm ( { ' title ' : ' Other ' , ' author ' : self . writer . pk , ' isbn ' : isbn } )
2010-03-17 03:32:11 +08:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' isbn ' ] , [ ' Derived book with this Isbn already exists. ' ] )
2010-03-17 03:32:11 +08:00
def test_abstract_inherited_unique_together ( self ) :
title = ' Boss '
isbn = ' 12345 '
2013-10-19 20:31:38 +08:00
DerivedBook . objects . create ( title = title , author = self . writer , isbn = isbn )
2011-06-10 22:08:51 +08:00
form = DerivedBookForm ( {
2013-10-20 07:33:10 +08:00
' title ' : ' Other ' ,
' author ' : self . writer . pk ,
' isbn ' : ' 9876 ' ,
' suffix1 ' : ' 0 ' ,
' suffix2 ' : ' 0 '
} )
2010-03-17 03:32:11 +08:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2011-06-10 22:08:51 +08:00
self . assertEqual ( form . errors [ ' __all__ ' ] ,
2012-06-08 00:08:47 +08:00
[ ' Derived book with this Suffix1 and Suffix2 already exists. ' ] )
2010-03-17 03:32:11 +08:00
def test_explicitpk_unspecified ( self ) :
""" Test for primary_key being in the form and failing validation. """
2013-10-15 03:13:14 +08:00
form = ExplicitPKForm ( { ' key ' : ' ' , ' desc ' : ' ' } )
2010-03-17 03:32:11 +08:00
self . assertFalse ( form . is_valid ( ) )
def test_explicitpk_unique ( self ) :
""" Ensure keys and blank character strings are tested for uniqueness. """
2012-06-08 00:08:47 +08:00
form = ExplicitPKForm ( { ' key ' : ' key1 ' , ' desc ' : ' ' } )
2010-03-17 03:32:11 +08:00
self . assertTrue ( form . is_valid ( ) )
form . save ( )
2012-06-08 00:08:47 +08:00
form = ExplicitPKForm ( { ' key ' : ' key1 ' , ' desc ' : ' ' } )
2010-03-17 03:32:11 +08:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 3 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' __all__ ' ] , [ ' Explicit pk with this Key and Desc already exists. ' ] )
self . assertEqual ( form . errors [ ' desc ' ] , [ ' Explicit pk with this Desc already exists. ' ] )
self . assertEqual ( form . errors [ ' key ' ] , [ ' Explicit pk with this Key already exists. ' ] )
2010-03-17 03:32:11 +08:00
def test_unique_for_date ( self ) :
p = Post . objects . create ( title = " Django 1.0 is released " ,
slug = " Django 1.0 " , subtitle = " Finally " , posted = datetime . date ( 2008 , 9 , 3 ) )
form = PostForm ( { ' title ' : " Django 1.0 is released " , ' posted ' : ' 2008-09-03 ' } )
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' title ' ] , [ ' Title must be unique for Posted date. ' ] )
2010-03-17 03:32:11 +08:00
form = PostForm ( { ' title ' : " Work on Django 1.1 begins " , ' posted ' : ' 2008-09-03 ' } )
self . assertTrue ( form . is_valid ( ) )
form = PostForm ( { ' title ' : " Django 1.0 is released " , ' posted ' : ' 2008-09-04 ' } )
self . assertTrue ( form . is_valid ( ) )
form = PostForm ( { ' slug ' : " Django 1.0 " , ' posted ' : ' 2008-01-01 ' } )
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' slug ' ] , [ ' Slug must be unique for Posted year. ' ] )
2010-03-17 03:32:11 +08:00
form = PostForm ( { ' subtitle ' : " Finally " , ' posted ' : ' 2008-09-30 ' } )
self . assertFalse ( form . is_valid ( ) )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' subtitle ' ] , [ ' Subtitle must be unique for Posted month. ' ] )
2010-03-17 03:32:11 +08:00
form = PostForm ( { ' subtitle ' : " Finally " , " title " : " Django 1.0 is released " ,
" slug " : " Django 1.0 " , ' posted ' : ' 2008-09-03 ' } , instance = p )
self . assertTrue ( form . is_valid ( ) )
2010-08-17 15:07:28 +08:00
form = PostForm ( { ' title ' : " Django 1.0 is released " } )
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' posted ' ] , [ ' This field is required. ' ] )
2010-03-17 03:32:11 +08:00
2013-05-28 21:56:14 +08:00
def test_unique_for_date_in_exclude ( self ) :
""" If the date for unique_for_* constraints is excluded from the
ModelForm ( in this case ' posted ' has editable = False , then the
constraint should be ignored . """
2013-10-19 20:31:38 +08:00
DateTimePost . objects . create ( title = " Django 1.0 is released " ,
2013-05-28 21:56:14 +08:00
slug = " Django 1.0 " , subtitle = " Finally " ,
posted = datetime . datetime ( 2008 , 9 , 3 , 10 , 10 , 1 ) )
# 'title' has unique_for_date='posted'
form = DateTimePostForm ( { ' title ' : " Django 1.0 is released " , ' posted ' : ' 2008-09-03 ' } )
self . assertTrue ( form . is_valid ( ) )
# 'slug' has unique_for_year='posted'
form = DateTimePostForm ( { ' slug ' : " Django 1.0 " , ' posted ' : ' 2008-01-01 ' } )
self . assertTrue ( form . is_valid ( ) )
# 'subtitle' has unique_for_month='posted'
form = DateTimePostForm ( { ' subtitle ' : " Finally " , ' posted ' : ' 2008-09-30 ' } )
self . assertTrue ( form . is_valid ( ) )
2010-03-17 03:32:11 +08:00
def test_inherited_unique_for_date ( self ) :
p = Post . objects . create ( title = " Django 1.0 is released " ,
slug = " Django 1.0 " , subtitle = " Finally " , posted = datetime . date ( 2008 , 9 , 3 ) )
form = DerivedPostForm ( { ' title ' : " Django 1.0 is released " , ' posted ' : ' 2008-09-03 ' } )
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' title ' ] , [ ' Title must be unique for Posted date. ' ] )
2010-03-17 03:32:11 +08:00
form = DerivedPostForm ( { ' title ' : " Work on Django 1.1 begins " , ' posted ' : ' 2008-09-03 ' } )
self . assertTrue ( form . is_valid ( ) )
form = DerivedPostForm ( { ' title ' : " Django 1.0 is released " , ' posted ' : ' 2008-09-04 ' } )
self . assertTrue ( form . is_valid ( ) )
form = DerivedPostForm ( { ' slug ' : " Django 1.0 " , ' posted ' : ' 2008-01-01 ' } )
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' slug ' ] , [ ' Slug must be unique for Posted year. ' ] )
2010-03-17 03:32:11 +08:00
form = DerivedPostForm ( { ' subtitle ' : " Finally " , ' posted ' : ' 2008-09-30 ' } )
self . assertFalse ( form . is_valid ( ) )
2012-06-08 00:08:47 +08:00
self . assertEqual ( form . errors [ ' subtitle ' ] , [ ' Subtitle must be unique for Posted month. ' ] )
2010-03-17 03:32:11 +08:00
form = DerivedPostForm ( { ' subtitle ' : " Finally " , " title " : " Django 1.0 is released " ,
" slug " : " Django 1.0 " , ' posted ' : ' 2008-09-03 ' } , instance = p )
self . assertTrue ( form . is_valid ( ) )
2011-01-09 21:26:39 +08:00
def test_unique_for_date_with_nullable_date ( self ) :
p = FlexibleDatePost . objects . create ( title = " Django 1.0 is released " ,
slug = " Django 1.0 " , subtitle = " Finally " , posted = datetime . date ( 2008 , 9 , 3 ) )
form = FlexDatePostForm ( { ' title ' : " Django 1.0 is released " } )
self . assertTrue ( form . is_valid ( ) )
form = FlexDatePostForm ( { ' slug ' : " Django 1.0 " } )
self . assertTrue ( form . is_valid ( ) )
form = FlexDatePostForm ( { ' subtitle ' : " Finally " } )
self . assertTrue ( form . is_valid ( ) )
form = FlexDatePostForm ( { ' subtitle ' : " Finally " , " title " : " Django 1.0 is released " ,
" slug " : " Django 1.0 " } , instance = p )
self . assertTrue ( form . is_valid ( ) )
2011-06-10 22:08:51 +08:00
2014-02-04 02:31:27 +08:00
def test_override_unique_message ( self ) :
class CustomProductForm ( ProductForm ) :
class Meta ( ProductForm . Meta ) :
error_messages = {
' slug ' : {
' unique ' : " %(model_name)s ' s %(field_label)s not unique. " ,
}
}
Product . objects . create ( slug = ' teddy-bear-blue ' )
form = CustomProductForm ( { ' slug ' : ' teddy-bear-blue ' } )
self . assertEqual ( len ( form . errors ) , 1 )
self . assertEqual ( form . errors [ ' slug ' ] , [ " Product ' s Slug not unique. " ] )
def test_override_unique_together_message ( self ) :
class CustomPriceForm ( PriceForm ) :
class Meta ( PriceForm . Meta ) :
error_messages = {
NON_FIELD_ERRORS : {
' unique_together ' : " %(model_name)s ' s %(field_labels)s not unique. " ,
}
}
Price . objects . create ( price = 6.00 , quantity = 1 )
form = CustomPriceForm ( { ' price ' : ' 6.00 ' , ' quantity ' : ' 1 ' } )
self . assertEqual ( len ( form . errors ) , 1 )
self . assertEqual ( form . errors [ NON_FIELD_ERRORS ] , [ " Price ' s Price and Quantity not unique. " ] )
def test_override_unique_for_date_message ( self ) :
class CustomPostForm ( PostForm ) :
class Meta ( PostForm . Meta ) :
error_messages = {
' title ' : {
' unique_for_date ' : " %(model_name)s ' s %(field_label)s not unique for %(date_field_label)s date. " ,
}
}
Post . objects . create ( title = " Django 1.0 is released " ,
slug = " Django 1.0 " , subtitle = " Finally " , posted = datetime . date ( 2008 , 9 , 3 ) )
form = CustomPostForm ( { ' title ' : " Django 1.0 is released " , ' posted ' : ' 2008-09-03 ' } )
self . assertEqual ( len ( form . errors ) , 1 )
self . assertEqual ( form . errors [ ' title ' ] , [ " Post ' s Title not unique for Posted date. " ] )
2013-11-03 06:50:35 +08:00
2012-11-05 07:42:17 +08:00
class ModelToDictTests ( TestCase ) :
"""
Tests for forms . models . model_to_dict
"""
def test_model_to_dict_many_to_many ( self ) :
2013-10-23 18:09:29 +08:00
categories = [
2012-11-05 07:42:17 +08:00
Category ( name = ' TestName1 ' , slug = ' TestName1 ' , url = ' url1 ' ) ,
Category ( name = ' TestName2 ' , slug = ' TestName2 ' , url = ' url2 ' ) ,
Category ( name = ' TestName3 ' , slug = ' TestName3 ' , url = ' url3 ' )
]
for c in categories :
c . save ( )
2013-06-10 18:22:40 +08:00
writer = Writer ( name = ' Test writer ' )
2012-11-05 07:42:17 +08:00
writer . save ( )
art = Article (
headline = ' Test article ' ,
slug = ' test-article ' ,
pub_date = datetime . date ( 1988 , 1 , 4 ) ,
writer = writer ,
article = ' Hello. '
)
art . save ( )
for c in categories :
art . categories . add ( c )
art . save ( )
with self . assertNumQueries ( 1 ) :
d = model_to_dict ( art )
2013-11-03 05:02:56 +08:00
# Ensure all many-to-many categories appear in model_to_dict
2012-11-05 07:42:17 +08:00
for c in categories :
self . assertIn ( c . pk , d [ ' categories ' ] )
2013-11-03 05:02:56 +08:00
# Ensure many-to-many relation appears as a list
2012-11-05 07:42:17 +08:00
self . assertIsInstance ( d [ ' categories ' ] , list )
2013-11-01 20:55:35 +08:00
def test_reuse_prefetched ( self ) :
# model_to_dict should not hit the database if it can reuse
# the data populated by prefetch_related.
categories = [
Category ( name = ' TestName1 ' , slug = ' TestName1 ' , url = ' url1 ' ) ,
Category ( name = ' TestName2 ' , slug = ' TestName2 ' , url = ' url2 ' ) ,
Category ( name = ' TestName3 ' , slug = ' TestName3 ' , url = ' url3 ' )
]
for c in categories :
c . save ( )
writer = Writer ( name = ' Test writer ' )
writer . save ( )
art = Article (
headline = ' Test article ' ,
slug = ' test-article ' ,
pub_date = datetime . date ( 1988 , 1 , 4 ) ,
writer = writer ,
article = ' Hello. '
)
art . save ( )
for c in categories :
art . categories . add ( c )
art = Article . objects . prefetch_related ( ' categories ' ) . get ( pk = art . pk )
with self . assertNumQueries ( 0 ) :
d = model_to_dict ( art )
#Ensure all many-to-many categories appear in model_to_dict
for c in categories :
self . assertIn ( c . pk , d [ ' categories ' ] )
#Ensure many-to-many relation appears as a list
self . assertIsInstance ( d [ ' categories ' ] , list )
2013-11-03 06:50:35 +08:00
2011-06-10 22:08:51 +08:00
class OldFormForXTests ( TestCase ) :
def test_base_form ( self ) :
self . assertEqual ( Category . objects . count ( ) , 0 )
f = BaseCategoryForm ( )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2011-06-10 22:08:51 +08:00
str ( f ) ,
""" <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_slug " > Slug : < / label > < / th > < td > < input id = " id_slug " type = " text " name = " slug " 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 > """
2013-10-18 17:02:43 +08:00
)
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2011-06-10 22:08:51 +08:00
str ( f . as_ul ( ) ) ,
""" <li><label for= " id_name " >Name:</label> <input id= " id_name " type= " text " name= " name " maxlength= " 20 " /></li>
< li > < label for = " id_slug " > Slug : < / label > < input id = " id_slug " type = " text " name = " slug " maxlength = " 20 " / > < / li >
< li > < label for = " id_url " > The URL : < / label > < input id = " id_url " type = " text " name = " url " maxlength = " 40 " / > < / li > """
2013-10-18 17:02:43 +08:00
)
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2011-06-10 22:08:51 +08:00
str ( f [ " name " ] ) ,
""" <input id= " id_name " type= " text " name= " name " maxlength= " 20 " /> """ )
def test_auto_id ( self ) :
f = BaseCategoryForm ( auto_id = False )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual (
2011-06-10 22:08:51 +08:00
str ( f . as_ul ( ) ) ,
""" <li>Name: <input type= " text " name= " name " maxlength= " 20 " /></li>
< li > Slug : < input type = " text " name = " slug " maxlength = " 20 " / > < / li >
< li > The URL : < input type = " text " name = " url " maxlength = " 40 " / > < / li > """
2013-10-18 17:02:43 +08:00
)
2011-06-10 22:08:51 +08:00
def test_with_data ( self ) :
self . assertEqual ( Category . objects . count ( ) , 0 )
f = BaseCategoryForm ( { ' name ' : ' Entertainment ' ,
' slug ' : ' entertainment ' ,
' url ' : ' entertainment ' } )
self . assertTrue ( f . is_valid ( ) )
self . assertEqual ( f . cleaned_data [ ' name ' ] , ' Entertainment ' )
self . assertEqual ( f . cleaned_data [ ' slug ' ] , ' entertainment ' )
self . assertEqual ( f . cleaned_data [ ' url ' ] , ' entertainment ' )
c1 = f . save ( )
# Testing wether the same object is returned from the
# ORM... not the fastest way...
self . assertEqual ( c1 , Category . objects . all ( ) [ 0 ] )
self . assertEqual ( c1 . name , " Entertainment " )
self . assertEqual ( Category . objects . count ( ) , 1 )
f = BaseCategoryForm ( { ' name ' : " It ' s a test " ,
' slug ' : ' its-test ' ,
' url ' : ' test ' } )
self . assertTrue ( f . is_valid ( ) )
self . assertEqual ( f . cleaned_data [ ' name ' ] , " It ' s a test " )
self . assertEqual ( f . cleaned_data [ ' slug ' ] , ' its-test ' )
self . assertEqual ( f . cleaned_data [ ' url ' ] , ' test ' )
c2 = f . save ( )
# Testing wether the same object is returned from the
# ORM... not the fastest way...
self . assertEqual ( c2 , Category . objects . get ( pk = c2 . pk ) )
self . assertEqual ( c2 . name , " It ' s a test " )
self . assertEqual ( Category . objects . count ( ) , 2 )
# If you call save() with commit=False, then it will return an object that
# hasn't yet been saved to the database. In this case, it's up to you to call
# save() on the resulting model instance.
f = BaseCategoryForm ( { ' name ' : ' Third test ' , ' slug ' : ' third-test ' , ' url ' : ' third ' } )
self . assertEqual ( f . is_valid ( ) , True )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . cleaned_data [ ' url ' ] , ' third ' )
self . assertEqual ( f . cleaned_data [ ' name ' ] , ' Third test ' )
self . assertEqual ( f . cleaned_data [ ' slug ' ] , ' third-test ' )
2011-06-10 22:08:51 +08:00
c3 = f . save ( commit = False )
self . assertEqual ( c3 . name , " Third test " )
self . assertEqual ( Category . objects . count ( ) , 2 )
c3 . save ( )
self . assertEqual ( Category . objects . count ( ) , 3 )
# If you call save() with invalid data, you'll get a ValueError.
f = BaseCategoryForm ( { ' name ' : ' ' , ' slug ' : ' not a slug! ' , ' url ' : ' foo ' } )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . errors [ ' name ' ] , [ ' This field is required. ' ] )
self . assertEqual ( f . errors [ ' slug ' ] , [ " Enter a valid ' slug ' consisting of letters, numbers, underscores or hyphens. " ] )
2012-08-04 20:17:02 +08:00
self . assertEqual ( f . cleaned_data , { ' url ' : ' foo ' } )
2011-06-10 22:08:51 +08:00
with self . assertRaises ( ValueError ) :
f . save ( )
f = BaseCategoryForm ( { ' name ' : ' ' , ' slug ' : ' ' , ' url ' : ' foo ' } )
with self . assertRaises ( ValueError ) :
f . save ( )
2013-06-10 18:22:40 +08:00
# Create a couple of Writers.
w_royko = Writer ( name = ' Mike Royko ' )
2011-06-10 22:08:51 +08:00
w_royko . save ( )
2013-06-10 18:22:40 +08:00
w_woodward = Writer ( name = ' Bob Woodward ' )
2011-06-10 22:08:51 +08:00
w_woodward . save ( )
# ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any
# fields with the 'choices' attribute are represented by a ChoiceField.
f = ArticleForm ( auto_id = False )
2012-07-20 20:48:51 +08:00
self . assertHTMLEqual ( six . text_type ( f ) , ''' <tr><th>Headline:</th><td><input type= " text " name= " headline " maxlength= " 50 " /></td></tr>
2011-06-10 22:08:51 +08:00
< tr > < th > Slug : < / th > < td > < input type = " text " name = " slug " 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 >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 22:08:51 +08:00
< / select > < / td > < / tr >
< tr > < th > Article : < / th > < td > < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / td > < / tr >
< tr > < th > Categories : < / th > < td > < select multiple = " multiple " name = " categories " >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
< option value = " %s " > Third test < / option >
2011-06-10 22:08:51 +08:00
< / select > < br / > < span class = " helptext " > Hold down " Control " , or " Command " on a Mac , to select more than one . < / span > < / td > < / tr >
< tr > < th > Status : < / th > < td > < select name = " status " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Draft < / option >
< option value = " 2 " > Pending < / option >
< option value = " 3 " > Live < / option >
2011-08-22 02:09:08 +08:00
< / select > < / td > < / tr > ''' % (w_woodward.pk, w_royko.pk, c1.pk, c2.pk, c3.pk))
2011-06-10 22:08:51 +08:00
# You can restrict a form to a subset of the complete list of fields
# by providing a 'fields' argument. If you try to save a
# model created with such a form, you need to ensure that the fields
# that are _not_ on the form have default values, or are allowed to have
# a value of None. If a field isn't specified on a form, the object created
# from the form can't provide a value for that field!
f = PartialArticleForm ( auto_id = False )
2012-07-20 20:48:51 +08:00
self . assertHTMLEqual ( six . text_type ( f ) , ''' <tr><th>Headline:</th><td><input type= " text " name= " headline " maxlength= " 50 " /></td></tr>
2011-06-10 22:08:51 +08:00
< tr > < th > Pub date : < / th > < td > < input type = " text " name = " pub_date " / > < / td > < / tr > ''' )
# When the ModelForm is passed an instance, that instance's current values are
# inserted as 'initial' data in each Field.
2013-06-10 18:22:40 +08:00
w = Writer . objects . get ( name = ' Mike Royko ' )
2011-06-10 22:08:51 +08:00
f = RoykoForm ( auto_id = False , instance = w )
2013-06-10 18:22:40 +08:00
self . assertHTMLEqual ( six . text_type ( f ) , ''' <tr><th>Name:</th><td><input type= " text " name= " name " value= " Mike Royko " maxlength= " 50 " /><br /><span class= " helptext " >Use both first and last names.</span></td></tr> ''' )
2011-06-10 22:08:51 +08:00
art = Article (
2013-10-20 07:33:10 +08:00
headline = ' Test article ' ,
slug = ' test-article ' ,
pub_date = datetime . date ( 1988 , 1 , 4 ) ,
writer = w ,
article = ' Hello. '
)
2011-06-10 22:08:51 +08:00
art . save ( )
art_id_1 = art . id
self . assertEqual ( art_id_1 is not None , True )
f = TestArticleForm ( auto_id = False , instance = art )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " value= " Test article " maxlength= " 50 " /></li>
2011-06-10 22:08:51 +08:00
< li > Slug : < input type = " text " name = " slug " 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 >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " selected = " selected " > Mike Royko < / option >
2011-06-10 22:08:51 +08:00
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > Hello . < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
< option value = " %s " > Third test < / option >
2011-06-10 22:08:51 +08:00
< / select > < span class = " helptext " > Hold down " Control " , or " Command " on a Mac , to select more than one . < / span > < / li >
< li > Status : < select name = " status " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Draft < / option >
< option value = " 2 " > Pending < / option >
< option value = " 3 " > Live < / option >
2011-08-22 02:09:08 +08:00
< / select > < / li > ''' % (w_woodward.pk, w_royko.pk, c1.pk, c2.pk, c3.pk))
2011-06-10 22:08:51 +08:00
f = TestArticleForm ( {
2013-10-20 07:33:10 +08:00
' headline ' : ' Test headline ' ,
' slug ' : ' test-headline ' ,
' pub_date ' : ' 1984-02-06 ' ,
' writer ' : six . text_type ( w_royko . pk ) ,
' article ' : ' Hello. '
2013-10-18 17:02:43 +08:00
} , instance = art )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . errors , { } )
self . assertEqual ( f . is_valid ( ) , True )
test_art = f . save ( )
self . assertEqual ( test_art . id == art_id_1 , True )
test_art = Article . objects . get ( id = art_id_1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( test_art . headline , ' Test headline ' )
2011-06-10 22:08:51 +08:00
# You can create a form over a subset of the available fields
# by specifying a 'fields' argument to form_for_instance.
f = PartialArticleFormWithSlug ( {
2013-10-20 07:33:10 +08:00
' headline ' : ' New headline ' ,
' slug ' : ' new-headline ' ,
' pub_date ' : ' 1988-01-04 '
2013-10-18 17:02:43 +08:00
} , auto_id = False , instance = art )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " value= " New headline " maxlength= " 50 " /></li>
2011-06-10 22:08:51 +08:00
< li > Slug : < input type = " text " name = " slug " value = " new-headline " maxlength = " 50 " / > < / li >
< li > Pub date : < input type = " text " name = " pub_date " value = " 1988-01-04 " / > < / li > ''' )
self . assertEqual ( f . is_valid ( ) , True )
new_art = f . save ( )
self . assertEqual ( new_art . id == art_id_1 , True )
new_art = Article . objects . get ( id = art_id_1 )
2012-06-08 00:08:47 +08:00
self . assertEqual ( new_art . headline , ' New headline ' )
2011-06-10 22:08:51 +08:00
# Add some categories and test the many-to-many form output.
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ ] )
2011-06-10 22:08:51 +08:00
new_art . categories . add ( Category . objects . get ( name = ' Entertainment ' ) )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ " Entertainment " ] )
2011-06-10 22:08:51 +08:00
f = TestArticleForm ( auto_id = False , instance = new_art )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " value= " New headline " maxlength= " 50 " /></li>
2011-06-10 22:08:51 +08:00
< li > Slug : < input type = " text " name = " slug " value = " new-headline " 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 >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " selected = " selected " > Mike Royko < / option >
2011-06-10 22:08:51 +08:00
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > Hello . < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
2011-08-22 02:09:08 +08:00
< option value = " %s " selected = " selected " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
< option value = " %s " > Third test < / option >
2011-06-10 22:08:51 +08:00
< / select > < span class = " helptext " > Hold down " Control " , or " Command " on a Mac , to select more than one . < / span > < / li >
< li > Status : < select name = " status " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Draft < / option >
< option value = " 2 " > Pending < / option >
< option value = " 3 " > Live < / option >
2011-08-22 02:09:08 +08:00
< / select > < / li > ''' % (w_woodward.pk, w_royko.pk, c1.pk, c2.pk, c3.pk))
2011-06-10 22:08:51 +08:00
# Initial values can be provided for model forms
f = TestArticleForm (
2013-10-20 07:33:10 +08:00
auto_id = False ,
initial = {
' headline ' : ' Your headline here ' ,
' categories ' : [ str ( c1 . id ) , str ( c2 . id ) ]
} )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " value= " Your headline here " maxlength= " 50 " /></li>
2011-06-10 22:08:51 +08:00
< li > Slug : < input type = " text " name = " slug " maxlength = " 50 " / > < / li >
< li > Pub date : < input type = " text " name = " pub_date " / > < / li >
< li > Writer : < select name = " writer " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 22:08:51 +08:00
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
2011-08-22 02:09:08 +08:00
< option value = " %s " selected = " selected " > Entertainment < / option >
< option value = " %s " selected = " selected " > It & #39;s a test</option>
< option value = " %s " > Third test < / option >
2011-06-10 22:08:51 +08:00
< / select > < span class = " helptext " > Hold down " Control " , or " Command " on a Mac , to select more than one . < / span > < / li >
< li > Status : < select name = " status " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Draft < / option >
< option value = " 2 " > Pending < / option >
< option value = " 3 " > Live < / option >
2011-08-22 02:09:08 +08:00
< / select > < / li > ''' % (w_woodward.pk, w_royko.pk, c1.pk, c2.pk, c3.pk))
2011-06-10 22:08:51 +08:00
f = TestArticleForm ( {
2013-10-20 07:33:10 +08:00
' headline ' : ' New headline ' ,
' slug ' : ' new-headline ' ,
' pub_date ' : ' 1988-01-04 ' ,
' writer ' : six . text_type ( w_royko . pk ) ,
' article ' : ' Hello. ' ,
' categories ' : [ six . text_type ( c1 . id ) , six . text_type ( c2 . id ) ]
2013-10-18 17:02:43 +08:00
} , instance = new_art )
2011-06-10 22:08:51 +08:00
new_art = f . save ( )
self . assertEqual ( new_art . id == art_id_1 , True )
new_art = Article . objects . get ( id = art_id_1 )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( new_art . categories . order_by ( ' name ' ) ,
2011-06-10 22:08:51 +08:00
[ " Entertainment " , " It ' s a test " ] )
# Now, submit form data with no categories. This deletes the existing categories.
2012-06-08 00:08:47 +08:00
f = TestArticleForm ( { ' headline ' : ' New headline ' , ' slug ' : ' new-headline ' , ' pub_date ' : ' 1988-01-04 ' ,
2012-07-20 20:48:51 +08:00
' writer ' : six . text_type ( w_royko . pk ) , ' article ' : ' Hello. ' } , instance = new_art )
2011-06-10 22:08:51 +08:00
new_art = f . save ( )
self . assertEqual ( new_art . id == art_id_1 , True )
new_art = Article . objects . get ( id = art_id_1 )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ ] )
2011-06-10 22:08:51 +08:00
# Create a new article, with categories, via the form.
2012-06-08 00:08:47 +08:00
f = ArticleForm ( { ' headline ' : ' The walrus was Paul ' , ' slug ' : ' walrus-was-paul ' , ' pub_date ' : ' 1967-11-01 ' ,
2012-07-20 20:48:51 +08:00
' writer ' : six . text_type ( w_royko . pk ) , ' article ' : ' Test. ' , ' categories ' : [ six . text_type ( c1 . id ) , six . text_type ( c2 . id ) ] } )
2011-06-10 22:08:51 +08:00
new_art = f . save ( )
art_id_2 = new_art . id
self . assertEqual ( art_id_2 not in ( None , art_id_1 ) , True )
new_art = Article . objects . get ( id = art_id_2 )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( new_art . categories . order_by ( ' name ' ) , [ " Entertainment " , " It ' s a test " ] )
2011-06-10 22:08:51 +08:00
# Create a new article, with no categories, via the form.
2012-06-08 00:08:47 +08:00
f = ArticleForm ( { ' headline ' : ' The walrus was Paul ' , ' slug ' : ' walrus-was-paul ' , ' pub_date ' : ' 1967-11-01 ' ,
2012-07-20 20:48:51 +08:00
' writer ' : six . text_type ( w_royko . pk ) , ' article ' : ' Test. ' } )
2011-06-10 22:08:51 +08:00
new_art = f . save ( )
art_id_3 = new_art . id
self . assertEqual ( art_id_3 not in ( None , art_id_1 , art_id_2 ) , True )
new_art = Article . objects . get ( id = art_id_3 )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ ] )
2011-06-10 22:08:51 +08:00
# Create a new article, with categories, via the form, but use commit=False.
# The m2m data won't be saved until save_m2m() is invoked on the form.
2012-06-08 00:08:47 +08:00
f = ArticleForm ( { ' headline ' : ' The walrus was Paul ' , ' slug ' : ' walrus-was-paul ' , ' pub_date ' : ' 1967-11-01 ' ,
2012-07-20 20:48:51 +08:00
' writer ' : six . text_type ( w_royko . pk ) , ' article ' : ' Test. ' , ' categories ' : [ six . text_type ( c1 . id ) , six . text_type ( c2 . id ) ] } )
2011-06-10 22:08:51 +08:00
new_art = f . save ( commit = False )
# Manually save the instance
new_art . save ( )
art_id_4 = new_art . id
self . assertEqual ( art_id_4 not in ( None , art_id_1 , art_id_2 , art_id_3 ) , True )
# The instance doesn't have m2m data yet
new_art = Article . objects . get ( id = art_id_4 )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ ] )
2011-06-10 22:08:51 +08:00
# Save the m2m data on the form
f . save_m2m ( )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( new_art . categories . order_by ( ' name ' ) , [ " Entertainment " , " It ' s a test " ] )
2011-06-10 22:08:51 +08:00
# Here, we define a custom ModelForm. Because it happens to have the same fields as
# the Category model, we can just call the form's save() to apply its changes to an
# existing Category instance.
cat = Category . objects . get ( name = ' Third test ' )
self . assertEqual ( cat . name , " Third test " )
self . assertEqual ( cat . id == c3 . id , True )
form = ShortCategory ( { ' name ' : ' Third ' , ' slug ' : ' third ' , ' url ' : ' 3rd ' } , instance = cat )
self . assertEqual ( form . save ( ) . name , ' Third ' )
self . assertEqual ( Category . objects . get ( id = c3 . id ) . name , ' Third ' )
# Here, we demonstrate that choices for a ForeignKey ChoiceField are determined
# at runtime, based on the data in the database when the form is displayed, not
# the data in the database when the form is instantiated.
f = ArticleForm ( auto_id = False )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " maxlength= " 50 " /></li>
2011-06-10 22:08:51 +08:00
< li > Slug : < input type = " text " name = " slug " maxlength = " 50 " / > < / li >
< li > Pub date : < input type = " text " name = " pub_date " / > < / li >
< li > Writer : < select name = " writer " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 22:08:51 +08:00
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
< option value = " %s " > Third < / option >
2011-06-10 22:08:51 +08:00
< / select > < span class = " helptext " > Hold down " Control " , or " Command " on a Mac , to select more than one . < / span > < / li >
< li > Status : < select name = " status " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Draft < / option >
< option value = " 2 " > Pending < / option >
< option value = " 3 " > Live < / option >
2011-08-22 02:09:08 +08:00
< / select > < / li > ''' % (w_woodward.pk, w_royko.pk, c1.pk, c2.pk, c3.pk))
2011-06-10 22:08:51 +08:00
c4 = Category . objects . create ( name = ' Fourth ' , url = ' 4th ' )
self . assertEqual ( c4 . name , ' Fourth ' )
2013-06-10 18:22:40 +08:00
w_bernstein = Writer . objects . create ( name = ' Carl Bernstein ' )
2011-08-22 02:09:08 +08:00
self . assertEqual ( w_bernstein . name , ' Carl Bernstein ' )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " maxlength= " 50 " /></li>
2011-06-10 22:08:51 +08:00
< li > Slug : < input type = " text " name = " slug " maxlength = " 50 " / > < / li >
< li > Pub date : < input type = " text " name = " pub_date " / > < / li >
< li > Writer : < select name = " writer " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Carl Bernstein < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 22:08:51 +08:00
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
< option value = " %s " > Third < / option >
< option value = " %s " > Fourth < / option >
2011-06-10 22:08:51 +08:00
< / select > < span class = " helptext " > Hold down " Control " , or " Command " on a Mac , to select more than one . < / span > < / li >
< li > Status : < select name = " status " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Draft < / option >
< option value = " 2 " > Pending < / option >
< option value = " 3 " > Live < / option >
2011-08-22 02:09:08 +08:00
< / select > < / li > ''' % (w_woodward.pk, w_bernstein.pk, w_royko.pk, c1.pk, c2.pk, c3.pk, c4.pk))
2011-06-10 22:08:51 +08:00
# ModelChoiceField ############################################################
f = forms . ModelChoiceField ( Category . objects . all ( ) )
self . assertEqual ( list ( f . choices ) , [
2012-06-08 00:08:47 +08:00
( ' ' , ' --------- ' ) ,
( c1 . pk , ' Entertainment ' ) ,
( c2 . pk , " It ' s a test " ) ,
( c3 . pk , ' Third ' ) ,
( c4 . pk , ' Fourth ' ) ] )
2013-02-24 03:11:47 +08:00
self . assertEqual ( 5 , len ( f . choices ) )
2011-06-10 22:08:51 +08:00
with self . assertRaises ( ValidationError ) :
f . clean ( ' ' )
with self . assertRaises ( ValidationError ) :
f . clean ( None )
with self . assertRaises ( ValidationError ) :
f . clean ( 0 )
self . assertEqual ( f . clean ( c3 . id ) . name , ' Third ' )
self . assertEqual ( f . clean ( c2 . id ) . name , " It ' s a test " )
# Add a Category object *after* the ModelChoiceField has already been
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
c5 = Category . objects . create ( name = ' Fifth ' , url = ' 5th ' )
self . assertEqual ( c5 . name , ' Fifth ' )
self . assertEqual ( f . clean ( c5 . id ) . name , ' Fifth ' )
# Delete a Category object *after* the ModelChoiceField has already been
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
Category . objects . get ( url = ' 5th ' ) . delete ( )
with self . assertRaises ( ValidationError ) :
f . clean ( c5 . id )
f = forms . ModelChoiceField ( Category . objects . filter ( pk = c1 . id ) , required = False )
self . assertEqual ( f . clean ( ' ' ) , None )
f . clean ( ' ' )
self . assertEqual ( f . clean ( str ( c1 . id ) ) . name , " Entertainment " )
with self . assertRaises ( ValidationError ) :
f . clean ( ' 100 ' )
# queryset can be changed after the field is created.
f . queryset = Category . objects . exclude ( name = ' Fourth ' )
self . assertEqual ( list ( f . choices ) , [
2012-06-08 00:08:47 +08:00
( ' ' , ' --------- ' ) ,
( c1 . pk , ' Entertainment ' ) ,
( c2 . pk , " It ' s a test " ) ,
( c3 . pk , ' Third ' ) ] )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . clean ( c3 . id ) . name , ' Third ' )
with self . assertRaises ( ValidationError ) :
f . clean ( c4 . id )
# check that we can safely iterate choices repeatedly
gen_one = list ( f . choices )
gen_two = f . choices
2012-06-08 00:08:47 +08:00
self . assertEqual ( gen_one [ 2 ] , ( c2 . pk , " It ' s a test " ) )
2011-06-10 22:08:51 +08:00
self . assertEqual ( list ( gen_two ) , [
2012-06-08 00:08:47 +08:00
( ' ' , ' --------- ' ) ,
( c1 . pk , ' Entertainment ' ) ,
( c2 . pk , " It ' s a test " ) ,
( c3 . pk , ' Third ' ) ] )
2011-06-10 22:08:51 +08:00
# check that we can override the label_from_instance method to print custom labels (#4620)
f . queryset = Category . objects . all ( )
f . label_from_instance = lambda obj : " category " + str ( obj )
self . assertEqual ( list ( f . choices ) , [
2012-06-08 00:08:47 +08:00
( ' ' , ' --------- ' ) ,
2011-08-22 02:09:08 +08:00
( c1 . pk , ' category Entertainment ' ) ,
( c2 . pk , " category It ' s a test " ) ,
( c3 . pk , ' category Third ' ) ,
( c4 . pk , ' category Fourth ' ) ] )
2011-06-10 22:08:51 +08:00
# ModelMultipleChoiceField ####################################################
f = forms . ModelMultipleChoiceField ( Category . objects . all ( ) )
self . assertEqual ( list ( f . choices ) , [
2012-06-08 00:08:47 +08:00
( c1 . pk , ' Entertainment ' ) ,
( c2 . pk , " It ' s a test " ) ,
( c3 . pk , ' Third ' ) ,
( c4 . pk , ' Fourth ' ) ] )
2011-06-10 22:08:51 +08:00
with self . assertRaises ( ValidationError ) :
f . clean ( None )
with self . assertRaises ( ValidationError ) :
f . clean ( [ ] )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( f . clean ( [ c1 . id ] ) , [ " Entertainment " ] )
self . assertQuerysetEqual ( f . clean ( [ c2 . id ] ) , [ " It ' s a test " ] )
self . assertQuerysetEqual ( f . clean ( [ str ( c1 . id ) ] ) , [ " Entertainment " ] )
2012-12-13 19:33:11 +08:00
self . assertQuerysetEqual ( f . clean ( [ str ( c1 . id ) , str ( c2 . id ) ] ) , [ " Entertainment " , " It ' s a test " ] ,
ordered = False )
self . assertQuerysetEqual ( f . clean ( [ c1 . id , str ( c2 . id ) ] ) , [ " Entertainment " , " It ' s a test " ] ,
ordered = False )
self . assertQuerysetEqual ( f . clean ( ( c1 . id , str ( c2 . id ) ) ) , [ " Entertainment " , " It ' s a test " ] ,
ordered = False )
2011-06-10 22:08:51 +08:00
with self . assertRaises ( ValidationError ) :
f . clean ( [ ' 100 ' ] )
with self . assertRaises ( ValidationError ) :
f . clean ( ' hello ' )
with self . assertRaises ( ValidationError ) :
f . clean ( [ ' fail ' ] )
# Add a Category object *after* the ModelMultipleChoiceField has already been
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
2012-11-05 10:23:03 +08:00
# Note, we are using an id of 1006 here since tests that run before
# this may create categories with primary keys up to 6. Use
# a number that is will not conflict.
c6 = Category . objects . create ( id = 1006 , name = ' Sixth ' , url = ' 6th ' )
2011-06-10 22:08:51 +08:00
self . assertEqual ( c6 . name , ' Sixth ' )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( f . clean ( [ c6 . id ] ) , [ " Sixth " ] )
2011-06-10 22:08:51 +08:00
# Delete a Category object *after* the ModelMultipleChoiceField has already been
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
Category . objects . get ( url = ' 6th ' ) . delete ( )
with self . assertRaises ( ValidationError ) :
f . clean ( [ c6 . id ] )
f = forms . ModelMultipleChoiceField ( Category . objects . all ( ) , required = False )
2012-10-04 00:50:12 +08:00
self . assertIsInstance ( f . clean ( [ ] ) , EmptyQuerySet )
self . assertIsInstance ( f . clean ( ( ) ) , EmptyQuerySet )
2011-06-10 22:08:51 +08:00
with self . assertRaises ( ValidationError ) :
2013-11-03 21:16:48 +08:00
f . clean ( [ ' 0 ' ] )
2011-06-10 22:08:51 +08:00
with self . assertRaises ( ValidationError ) :
2013-11-03 21:16:48 +08:00
f . clean ( [ str ( c3 . id ) , ' 0 ' ] )
2011-06-10 22:08:51 +08:00
with self . assertRaises ( ValidationError ) :
2013-11-03 21:16:48 +08:00
f . clean ( [ str ( c1 . id ) , ' 0 ' ] )
2011-06-10 22:08:51 +08:00
# queryset can be changed after the field is created.
f . queryset = Category . objects . exclude ( name = ' Fourth ' )
self . assertEqual ( list ( f . choices ) , [
2012-06-08 00:08:47 +08:00
( c1 . pk , ' Entertainment ' ) ,
( c2 . pk , " It ' s a test " ) ,
( c3 . pk , ' Third ' ) ] )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( f . clean ( [ c3 . id ] ) , [ " Third " ] )
2011-06-10 22:08:51 +08:00
with self . assertRaises ( ValidationError ) :
f . clean ( [ c4 . id ] )
with self . assertRaises ( ValidationError ) :
f . clean ( [ str ( c3 . id ) , str ( c4 . id ) ] )
f . queryset = Category . objects . all ( )
f . label_from_instance = lambda obj : " multicategory " + str ( obj )
self . assertEqual ( list ( f . choices ) , [
2011-08-22 02:09:08 +08:00
( c1 . pk , ' multicategory Entertainment ' ) ,
( c2 . pk , " multicategory It ' s a test " ) ,
( c3 . pk , ' multicategory Third ' ) ,
( c4 . pk , ' multicategory Fourth ' ) ] )
2011-06-10 22:08:51 +08:00
# OneToOneField ###############################################################
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( ImprovedArticleForm . base_fields ) , [ ' article ' ] )
2011-06-10 22:08:51 +08:00
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( ImprovedArticleWithParentLinkForm . base_fields ) , [ ] )
2011-06-10 22:08:51 +08:00
2013-06-10 18:22:40 +08:00
bw = BetterWriter ( name = ' Joe Better ' , score = 10 )
2011-06-10 22:08:51 +08:00
bw . save ( )
2012-08-15 05:38:35 +08:00
self . assertEqual ( sorted ( model_to_dict ( bw ) ) ,
2013-06-10 18:22:40 +08:00
[ ' id ' , ' name ' , ' score ' , ' writer_ptr ' ] )
2011-06-10 22:08:51 +08:00
2013-06-10 18:22:40 +08:00
form = BetterWriterForm ( { ' name ' : ' Some Name ' , ' score ' : 12 } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( form . is_valid ( ) , True )
bw2 = form . save ( )
bw2 . delete ( )
2013-06-10 18:22:40 +08:00
form = WriterProfileForm ( )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual ( form . as_p ( ) , ''' <p><label for= " id_writer " >Writer:</label> <select name= " writer " id= " id_writer " >
2011-06-10 22:08:51 +08:00
< option value = " " selected = " selected " > - - - - - - - - - < / option >
2011-08-22 02:09:08 +08:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Carl Bernstein < / option >
< option value = " %s " > Joe Better < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 22:08:51 +08:00
< / select > < / p >
2013-02-23 16:45:56 +08:00
< p > < label for = " id_age " > Age : < / label > < input type = " number " name = " age " id = " id_age " min = " 0 " / > < / p > ''' % (w_woodward.pk, w_bernstein.pk, bw.pk, w_royko.pk))
2011-06-10 22:08:51 +08:00
data = {
2012-07-20 20:48:51 +08:00
' writer ' : six . text_type ( w_woodward . pk ) ,
2012-06-08 00:08:47 +08:00
' age ' : ' 65 ' ,
2011-06-10 22:08:51 +08:00
}
2013-06-10 18:22:40 +08:00
form = WriterProfileForm ( data )
2011-06-10 22:08:51 +08:00
instance = form . save ( )
2012-07-20 20:48:51 +08:00
self . assertEqual ( six . text_type ( instance ) , ' Bob Woodward is 65 ' )
2011-06-10 22:08:51 +08:00
2013-06-10 18:22:40 +08:00
form = WriterProfileForm ( instance = instance )
2012-02-01 04:36:11 +08:00
self . assertHTMLEqual ( form . as_p ( ) , ''' <p><label for= " id_writer " >Writer:</label> <select name= " writer " id= " id_writer " >
2011-06-10 22:08:51 +08:00
< option value = " " > - - - - - - - - - < / option >
2011-08-22 02:09:08 +08:00
< option value = " %s " selected = " selected " > Bob Woodward < / option >
< option value = " %s " > Carl Bernstein < / option >
< option value = " %s " > Joe Better < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 22:08:51 +08:00
< / select > < / p >
2013-02-23 16:45:56 +08:00
< p > < label for = " id_age " > Age : < / label > < input type = " number " name = " age " value = " 65 " id = " id_age " min = " 0 " / > < / p > ''' % (w_woodward.pk, w_bernstein.pk, bw.pk, w_royko.pk))
2011-06-10 22:08:51 +08:00
def test_file_field ( self ) :
# Test conditions when files is either not given or empty.
2012-06-08 00:08:47 +08:00
f = TextFileForm ( data = { ' description ' : ' Assistance ' } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , False )
2012-06-08 00:08:47 +08:00
f = TextFileForm ( data = { ' description ' : ' Assistance ' } , files = { } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , False )
# Upload a file and ensure it all works as expected.
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test1.txt ' , b ' hello world ' ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
self . assertEqual ( type ( f . cleaned_data [ ' file ' ] ) , SimpleUploadedFile )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' tests/test1.txt ' )
instance . file . delete ( )
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test1.txt ' , b ' hello world ' ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
self . assertEqual ( type ( f . cleaned_data [ ' file ' ] ) , SimpleUploadedFile )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' tests/test1.txt ' )
# Check if the max_length attribute has been inherited from the model.
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test-maxlength.txt ' , b ' hello world ' ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , False )
# Edit an instance that already has the file defined in the model. This will not
# save the file again, but leave it exactly as it is.
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Assistance ' } ,
instance = instance )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
self . assertEqual ( f . cleaned_data [ ' file ' ] . name , ' tests/test1.txt ' )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' tests/test1.txt ' )
# Delete the current file since this is not done by Django.
instance . file . delete ( )
# Override the file by uploading a new one.
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test2.txt ' , b ' hello world ' ) } , instance = instance )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' tests/test2.txt ' )
# Delete the current file since this is not done by Django.
instance . file . delete ( )
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test2.txt ' , b ' hello world ' ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' tests/test2.txt ' )
# Delete the current file since this is not done by Django.
instance . file . delete ( )
instance . delete ( )
# Test the non-required FileField
2012-06-08 00:08:47 +08:00
f = TextFileForm ( data = { ' description ' : ' Assistance ' } )
2011-06-10 22:08:51 +08:00
f . fields [ ' file ' ] . required = False
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' ' )
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test3.txt ' , b ' hello world ' ) } , instance = instance )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' tests/test3.txt ' )
# Instance can be edited w/out re-uploading the file and existing file should be preserved.
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' New Description ' } ,
instance = instance )
2011-06-10 22:08:51 +08:00
f . fields [ ' file ' ] . required = False
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
2012-06-08 00:08:47 +08:00
self . assertEqual ( instance . description , ' New Description ' )
2011-06-10 22:08:51 +08:00
self . assertEqual ( instance . file . name , ' tests/test3.txt ' )
# Delete the current file since this is not done by Django.
instance . file . delete ( )
instance . delete ( )
f = TextFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test3.txt ' , b ' hello world ' ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' tests/test3.txt ' )
# Delete the current file since this is not done by Django.
instance . file . delete ( )
instance . delete ( )
def test_big_integer_field ( self ) :
bif = BigIntForm ( { ' biggie ' : ' -9223372036854775808 ' } )
self . assertEqual ( bif . is_valid ( ) , True )
bif = BigIntForm ( { ' biggie ' : ' -9223372036854775809 ' } )
self . assertEqual ( bif . is_valid ( ) , False )
2012-06-08 00:08:47 +08:00
self . assertEqual ( bif . errors , { ' biggie ' : [ ' Ensure this value is greater than or equal to -9223372036854775808. ' ] } )
2011-06-10 22:08:51 +08:00
bif = BigIntForm ( { ' biggie ' : ' 9223372036854775807 ' } )
self . assertEqual ( bif . is_valid ( ) , True )
bif = BigIntForm ( { ' biggie ' : ' 9223372036854775808 ' } )
self . assertEqual ( bif . is_valid ( ) , False )
2012-06-08 00:08:47 +08:00
self . assertEqual ( bif . errors , { ' biggie ' : [ ' Ensure this value is less than or equal to 9223372036854775807. ' ] } )
2011-06-10 22:08:51 +08:00
2013-11-26 13:52:47 +08:00
@skipUnless ( test_images , " Pillow/PIL not installed " )
2011-06-10 22:08:51 +08:00
def test_image_field ( self ) :
# ImageField and FileField are nearly identical, but they differ slighty when
# it comes to validation. This specifically tests that #6302 is fixed for
# both file fields and image fields.
2012-12-08 18:13:52 +08:00
with open ( os . path . join ( os . path . dirname ( upath ( __file__ ) ) , " test.png " ) , ' rb ' ) as fp :
2012-05-05 20:01:38 +08:00
image_data = fp . read ( )
2012-12-08 18:13:52 +08:00
with open ( os . path . join ( os . path . dirname ( upath ( __file__ ) ) , " test2.png " ) , ' rb ' ) as fp :
2012-05-05 20:01:38 +08:00
image_data2 = fp . read ( )
2011-06-10 22:08:51 +08:00
f = ImageFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' An image ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test.png ' , image_data ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
self . assertEqual ( type ( f . cleaned_data [ ' image ' ] ) , SimpleUploadedFile )
instance = f . save ( )
self . assertEqual ( instance . image . name , ' tests/test.png ' )
self . assertEqual ( instance . width , 16 )
self . assertEqual ( instance . height , 16 )
# Delete the current file since this is not done by Django, but don't save
# because the dimension fields are not null=True.
instance . image . delete ( save = False )
f = ImageFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' An image ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test.png ' , image_data ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
self . assertEqual ( type ( f . cleaned_data [ ' image ' ] ) , SimpleUploadedFile )
instance = f . save ( )
self . assertEqual ( instance . image . name , ' tests/test.png ' )
self . assertEqual ( instance . width , 16 )
self . assertEqual ( instance . height , 16 )
# Edit an instance that already has the (required) image defined in the model. This will not
# save the image again, but leave it exactly as it is.
2012-06-08 00:08:47 +08:00
f = ImageFileForm ( data = { ' description ' : ' Look, it changed ' } , instance = instance )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
self . assertEqual ( f . cleaned_data [ ' image ' ] . name , ' tests/test.png ' )
instance = f . save ( )
self . assertEqual ( instance . image . name , ' tests/test.png ' )
self . assertEqual ( instance . height , 16 )
self . assertEqual ( instance . width , 16 )
# Delete the current file since this is not done by Django, but don't save
# because the dimension fields are not null=True.
instance . image . delete ( save = False )
# Override the file by uploading a new one.
f = ImageFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Changed it ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test2.png ' , image_data2 ) } , instance = instance )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . image . name , ' tests/test2.png ' )
self . assertEqual ( instance . height , 32 )
self . assertEqual ( instance . width , 48 )
# Delete the current file since this is not done by Django, but don't save
# because the dimension fields are not null=True.
instance . image . delete ( save = False )
instance . delete ( )
f = ImageFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' Changed it ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test2.png ' , image_data2 ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . image . name , ' tests/test2.png ' )
self . assertEqual ( instance . height , 32 )
self . assertEqual ( instance . width , 48 )
# Delete the current file since this is not done by Django, but don't save
# because the dimension fields are not null=True.
instance . image . delete ( save = False )
instance . delete ( )
# Test the non-required ImageField
2012-06-08 00:08:47 +08:00
# Note: In Oracle, we expect a null ImageField to return '' instead of
2011-10-01 05:40:56 +08:00
# None.
if connection . features . interprets_empty_strings_as_nulls :
2012-06-08 00:08:47 +08:00
expected_null_imagefield_repr = ' '
2011-10-01 05:40:56 +08:00
else :
expected_null_imagefield_repr = None
2011-06-10 22:08:51 +08:00
2012-06-08 00:08:47 +08:00
f = OptionalImageFileForm ( data = { ' description ' : ' Test ' } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
2011-10-01 05:40:56 +08:00
self . assertEqual ( instance . image . name , expected_null_imagefield_repr )
2011-06-10 22:08:51 +08:00
self . assertEqual ( instance . width , None )
self . assertEqual ( instance . height , None )
f = OptionalImageFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' And a final one ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test3.png ' , image_data ) } , instance = instance )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . image . name , ' tests/test3.png ' )
self . assertEqual ( instance . width , 16 )
self . assertEqual ( instance . height , 16 )
# Editing the instance without re-uploading the image should not affect the image or its width/height properties
f = OptionalImageFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' New Description ' } ,
instance = instance )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
2012-06-08 00:08:47 +08:00
self . assertEqual ( instance . description , ' New Description ' )
2011-06-10 22:08:51 +08:00
self . assertEqual ( instance . image . name , ' tests/test3.png ' )
self . assertEqual ( instance . width , 16 )
self . assertEqual ( instance . height , 16 )
# Delete the current file since this is not done by Django.
instance . image . delete ( )
instance . delete ( )
f = OptionalImageFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' And a final one ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test4.png ' , image_data2 ) }
2013-10-18 17:02:43 +08:00
)
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . image . name , ' tests/test4.png ' )
self . assertEqual ( instance . width , 48 )
self . assertEqual ( instance . height , 32 )
instance . delete ( )
# Test callable upload_to behavior that's dependent on the value of another field in the model
f = ImageFileForm (
2013-10-20 07:33:10 +08:00
data = { ' description ' : ' And a final one ' , ' path ' : ' foo ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test4.png ' , image_data ) } )
2011-06-10 22:08:51 +08:00
self . assertEqual ( f . is_valid ( ) , True )
instance = f . save ( )
self . assertEqual ( instance . image . name , ' foo/test4.png ' )
instance . delete ( )
def test_media_on_modelform ( self ) :
# Similar to a regular Form class you can define custom media to be used on
# the ModelForm.
f = ModelFormWithMedia ( )
2012-07-20 20:48:51 +08:00
self . assertHTMLEqual ( six . text_type ( f . media ) , ''' <link href= " /some/form/css " type= " text/css " media= " all " rel= " stylesheet " />
2011-06-10 22:08:51 +08:00
< script type = " text/javascript " src = " /some/form/javascript " > < / script > ''' )
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,2,3 ' } )
self . assertEqual ( f . is_valid ( ) , True )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . cleaned_data , { ' field ' : ' 1,2,3 ' } )
2011-06-10 22:08:51 +08:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1a,2 ' } )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . errors , { ' field ' : [ ' Enter only digits separated by commas. ' ] } )
2011-06-10 22:08:51 +08:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' ,,,, ' } )
self . assertEqual ( f . is_valid ( ) , True )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . cleaned_data , { ' field ' : ' ,,,, ' } )
2011-06-10 22:08:51 +08:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1.2 ' } )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . errors , { ' field ' : [ ' Enter only digits separated by commas. ' ] } )
2011-06-10 22:08:51 +08:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,a,2 ' } )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . errors , { ' field ' : [ ' Enter only digits separated by commas. ' ] } )
2011-06-10 22:08:51 +08:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,,2 ' } )
self . assertEqual ( f . is_valid ( ) , True )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . cleaned_data , { ' field ' : ' 1,,2 ' } )
2011-06-10 22:08:51 +08:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1 ' } )
self . assertEqual ( f . is_valid ( ) , True )
2012-06-08 00:08:47 +08:00
self . assertEqual ( f . cleaned_data , { ' field ' : ' 1 ' } )
2011-06-10 22:08:51 +08:00
# This Price instance generated by this form is not valid because the quantity
# field is required, but the form is valid because the field is excluded from
# the form. This is for backwards compatibility.
form = PriceFormWithoutQuantity ( { ' price ' : ' 6.00 ' } )
self . assertEqual ( form . is_valid ( ) , True )
price = form . save ( commit = False )
with self . assertRaises ( ValidationError ) :
price . full_clean ( )
# The form should not validate fields that it doesn't contain even if they are
# specified using 'fields', not 'exclude'.
class Meta :
model = Price
fields = ( ' price ' , )
form = PriceFormWithoutQuantity ( { ' price ' : ' 6.00 ' } )
self . assertEqual ( form . is_valid ( ) , True )
# The form should still have an instance of a model that is not complete and
# not saved into a DB yet.
self . assertEqual ( form . instance . price , Decimal ( ' 6.00 ' ) )
self . assertEqual ( form . instance . quantity is None , True )
self . assertEqual ( form . instance . pk is None , True )
# Choices on CharField and IntegerField
f = ArticleForm ( )
with self . assertRaises ( ValidationError ) :
f . fields [ ' status ' ] . clean ( ' 42 ' )
f = ArticleStatusForm ( )
with self . assertRaises ( ValidationError ) :
f . fields [ ' status ' ] . clean ( ' z ' )
def test_foreignkeys_which_use_to_field ( self ) :
apple = Inventory . objects . create ( barcode = 86 , name = ' Apple ' )
2013-10-19 20:31:38 +08:00
Inventory . objects . create ( barcode = 22 , name = ' Pear ' )
2011-06-10 22:08:51 +08:00
core = Inventory . objects . create ( barcode = 87 , name = ' Core ' , parent = apple )
field = forms . ModelChoiceField ( Inventory . objects . all ( ) , to_field_name = ' barcode ' )
self . assertEqual ( tuple ( field . choices ) , (
2012-06-08 00:08:47 +08:00
( ' ' , ' --------- ' ) ,
( 86 , ' Apple ' ) ,
( 87 , ' Core ' ) ,
( 22 , ' Pear ' ) ) )
2011-06-10 22:08:51 +08:00
form = InventoryForm ( instance = core )
2012-07-20 20:48:51 +08:00
self . assertHTMLEqual ( six . text_type ( form [ ' parent ' ] ) , ''' <select name= " parent " id= " id_parent " >
2011-06-10 22:08:51 +08:00
< option value = " " > - - - - - - - - - < / option >
< option value = " 86 " selected = " selected " > Apple < / option >
< option value = " 87 " > Core < / option >
< option value = " 22 " > Pear < / option >
< / select > ''' )
data = model_to_dict ( core )
data [ ' parent ' ] = ' 22 '
form = InventoryForm ( data = data , instance = core )
core = form . save ( )
self . assertEqual ( core . parent . name , ' Pear ' )
class CategoryForm ( forms . ModelForm ) :
description = forms . CharField ( )
2013-10-22 18:21:07 +08:00
2011-06-10 22:08:51 +08:00
class Meta :
model = Category
fields = [ ' description ' , ' url ' ]
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( CategoryForm . base_fields ) ,
2011-06-10 22:08:51 +08:00
[ ' description ' , ' url ' ] )
2012-07-20 20:48:51 +08:00
self . assertHTMLEqual ( six . text_type ( CategoryForm ( ) ) , ''' <tr><th><label for= " id_description " >Description:</label></th><td><input type= " text " name= " description " id= " id_description " /></td></tr>
2011-06-10 22:08:51 +08:00
< tr > < th > < label for = " id_url " > The URL : < / label > < / th > < td > < input id = " id_url " type = " text " name = " url " maxlength = " 40 " / > < / td > < / tr > ''' )
# to_field_name should also work on ModelMultipleChoiceField ##################
field = forms . ModelMultipleChoiceField ( Inventory . objects . all ( ) , to_field_name = ' barcode ' )
2012-06-08 00:08:47 +08:00
self . assertEqual ( tuple ( field . choices ) , ( ( 86 , ' Apple ' ) , ( 87 , ' Core ' ) , ( 22 , ' Pear ' ) ) )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( field . clean ( [ 86 ] ) , [ ' Apple ' ] )
2011-06-10 22:08:51 +08:00
form = SelectInventoryForm ( { ' items ' : [ 87 , 22 ] } )
self . assertEqual ( form . is_valid ( ) , True )
self . assertEqual ( len ( form . cleaned_data ) , 1 )
2012-08-15 05:38:35 +08:00
self . assertQuerysetEqual ( form . cleaned_data [ ' items ' ] , [ ' Core ' , ' Pear ' ] )
2011-06-10 22:08:51 +08:00
def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields ( self ) :
2012-08-15 05:38:35 +08:00
self . assertEqual ( list ( CustomFieldForExclusionForm . base_fields ) ,
[ ' name ' ] )
2012-07-20 20:48:51 +08:00
self . assertHTMLEqual ( six . text_type ( CustomFieldForExclusionForm ( ) ) ,
2011-06-10 22:08:51 +08:00
''' <tr><th><label for= " id_name " >Name:</label></th><td><input id= " id_name " type= " text " name= " name " maxlength= " 10 " /></td></tr> ''' )
2012-12-20 02:12:08 +08:00
2013-10-27 09:27:42 +08:00
def test_iterable_model_m2m ( self ) :
2012-12-20 02:12:08 +08:00
colour = Colour . objects . create ( name = ' Blue ' )
form = ColourfulItemForm ( )
self . maxDiff = 1024
2012-12-29 22:25:24 +08:00
self . assertHTMLEqual (
form . as_p ( ) ,
""" <p><label for= " id_name " >Name:</label> <input id= " id_name " type= " text " name= " name " maxlength= " 50 " /></p>
2012-12-20 02:12:08 +08:00
< p > < label for = " id_colours " > Colours : < / label > < select multiple = " multiple " name = " colours " id = " id_colours " >
2012-12-29 22:25:24 +08:00
< option value = " %(blue_pk)s " > Blue < / option >
< / select > < span class = " helptext " > Hold down " Control " , or " Command " on a Mac , to select more than one . < / span > < / p > """
% { ' blue_pk ' : colour . pk } )
2013-05-22 05:32:39 +08:00
2013-10-27 09:27:42 +08:00
def test_custom_error_messages ( self ) :
2013-06-06 02:55:05 +08:00
data = { ' name1 ' : ' @#$!!**@#$ ' , ' name2 ' : ' @#$!!**@#$ ' }
errors = CustomErrorMessageForm ( data ) . errors
self . assertHTMLEqual (
str ( errors [ ' name1 ' ] ) ,
' <ul class= " errorlist " ><li>Form custom error message.</li></ul> '
)
self . assertHTMLEqual (
str ( errors [ ' name2 ' ] ) ,
' <ul class= " errorlist " ><li>Model custom error message.</li></ul> '
)
2013-10-27 09:27:42 +08:00
def test_model_clean_error_messages ( self ) :
2013-08-06 03:26:51 +08:00
data = { ' name1 ' : ' FORBIDDEN_VALUE ' , ' name2 ' : ' ABC ' }
errors = CustomErrorMessageForm ( data ) . errors
self . assertHTMLEqual (
str ( errors [ ' name1 ' ] ) ,
' <ul class= " errorlist " ><li>Model.clean() error messages.</li></ul> '
)
2013-05-22 05:32:39 +08:00
class M2mHelpTextTest ( TestCase ) :
""" Tests for ticket #9321. """
def test_multiple_widgets ( self ) :
""" Help text of different widgets for ManyToManyFields model fields """
dreaded_help_text = ' <span class= " helptext " > Hold down " Control " , or " Command " on a Mac, to select more than one.</span> '
# Default widget (SelectMultiple):
std_form = StatusNoteForm ( )
self . assertInHTML ( dreaded_help_text , std_form . as_p ( ) )
# Overridden widget (CheckboxSelectMultiple, a subclass of
# SelectMultiple but with a UI that doesn't involve Control/Command
# keystrokes to extend selection):
form = StatusNoteCBM2mForm ( )
html = form . as_p ( )
self . assertInHTML ( ' <ul id= " id_status " > ' , html )
self . assertInHTML ( dreaded_help_text , html , count = 0 )
2013-07-21 03:25:27 +08:00
class ModelFormInheritanceTests ( TestCase ) :
def test_form_subclass_inheritance ( self ) :
class Form ( forms . Form ) :
age = forms . IntegerField ( )
class ModelForm ( forms . ModelForm , Form ) :
class Meta :
model = Writer
fields = ' __all__ '
self . assertEqual ( list ( ModelForm ( ) . fields . keys ( ) ) , [ ' name ' , ' age ' ] )
2013-10-14 23:42:33 +08:00
def test_field_shadowing ( self ) :
class ModelForm ( forms . ModelForm ) :
class Meta :
model = Writer
fields = ' __all__ '
class Mixin ( object ) :
age = None
class Form ( forms . Form ) :
age = forms . IntegerField ( )
class Form2 ( forms . Form ) :
foo = forms . IntegerField ( )
self . assertEqual ( list ( ModelForm ( ) . fields . keys ( ) ) , [ ' name ' ] )
self . assertEqual ( list ( type ( str ( ' NewForm ' ) , ( Mixin , Form ) , { } ) ( ) . fields . keys ( ) ) , [ ] )
self . assertEqual ( list ( type ( str ( ' NewForm ' ) , ( Form2 , Mixin , Form ) , { } ) ( ) . fields . keys ( ) ) , [ ' foo ' ] )
self . assertEqual ( list ( type ( str ( ' NewForm ' ) , ( Mixin , ModelForm , Form ) , { } ) ( ) . fields . keys ( ) ) , [ ' name ' ] )
self . assertEqual ( list ( type ( str ( ' NewForm ' ) , ( ModelForm , Mixin , Form ) , { } ) ( ) . fields . keys ( ) ) , [ ' name ' ] )
self . assertEqual ( list ( type ( str ( ' NewForm ' ) , ( ModelForm , Form , Mixin ) , { } ) ( ) . fields . keys ( ) ) , [ ' name ' , ' age ' ] )
self . assertEqual ( list ( type ( str ( ' NewForm ' ) , ( ModelForm , Form ) , { ' age ' : None } ) ( ) . fields . keys ( ) ) , [ ' name ' ] )
2014-02-02 03:23:31 +08:00
class LimitChoicesToTest ( TestCase ) :
"""
Tests the functionality of ` ` limit_choices_to ` ` .
"""
def setUp ( self ) :
self . threepwood = Character . objects . create (
username = ' threepwood ' ,
last_action = datetime . datetime . today ( ) + datetime . timedelta ( days = 1 ) ,
)
self . marley = Character . objects . create (
username = ' marley ' ,
last_action = datetime . datetime . today ( ) - datetime . timedelta ( days = 1 ) ,
)
def test_limit_choices_to_callable_for_fk_rel ( self ) :
"""
A ForeignKey relation can use ` ` limit_choices_to ` ` as a callable , re #2554.
"""
stumpjokeform = StumpJokeForm ( )
self . assertIn ( self . threepwood , stumpjokeform . fields [ ' most_recently_fooled ' ] . queryset )
self . assertNotIn ( self . marley , stumpjokeform . fields [ ' most_recently_fooled ' ] . queryset )
def test_limit_choices_to_callable_for_m2m_rel ( self ) :
"""
A ManyToMany relation can use ` ` limit_choices_to ` ` as a callable , re #2554.
"""
stumpjokeform = StumpJokeForm ( )
self . assertIn ( self . threepwood , stumpjokeform . fields [ ' has_fooled_today ' ] . queryset )
self . assertNotIn ( self . marley , stumpjokeform . fields [ ' has_fooled_today ' ] . queryset )