2013-07-29 17:19:04 +00:00
from __future__ import unicode_literals
2011-06-10 14:49:44 +00:00
2010-03-16 19:32:11 +00:00
import datetime
2011-06-10 14:08:51 +00:00
import os
from decimal import Decimal
2013-07-01 12:22:27 +00:00
from unittest import skipUnless
2011-06-10 14:08:51 +00:00
2010-02-22 23:06:09 +00:00
from django import forms
2015-01-28 12:35:27 +00:00
from django . core . exceptions import (
NON_FIELD_ERRORS , FieldError , ImproperlyConfigured ,
)
2011-06-10 14:08:51 +00:00
from django . core . files . uploadedfile import SimpleUploadedFile
from django . core . validators import ValidationError
2015-02-06 21:19:23 +00:00
from django . db import connection , models
2012-10-03 16:50:12 +00:00
from django . db . models . query import EmptyQuerySet
2015-01-28 12:35:27 +00:00
from django . forms . models import (
ModelFormMetaclass , construct_instance , fields_for_model , model_to_dict ,
modelform_factory ,
)
from django . template import Context , Template
2014-01-08 14:53:40 +00:00
from django . test import TestCase , skipUnlessDBFeature
2012-07-20 12:48:51 +00:00
from django . utils import six
2015-01-28 12:35:27 +00:00
from django . utils . _os import upath
2011-06-10 14:08:51 +00:00
2015-01-28 12:35:27 +00:00
from . models import (
Article , ArticleStatus , Author , Author1 , BetterWriter , BigInt , Book ,
Category , Character , Colour , ColourfulItem , CommaSeparatedInteger ,
CustomErrorMessage , CustomFF , CustomFieldForExclusionModel , DateTimePost ,
DerivedBook , DerivedPost , Document , ExplicitPK , FilePathModel ,
FlexibleDatePost , Homepage , ImprovedArticle , ImprovedArticleWithParentLink ,
2015-03-04 19:19:02 +00:00
Inventory , Person , Photo , Post , Price , Product , Publication ,
PublicationDefaults , Student , StumpJoke , TextFile , Triple , Writer ,
WriterProfile , test_images ,
2015-01-28 12:35:27 +00:00
)
2011-06-10 14:08:51 +00:00
2011-06-13 13:23:49 +00:00
if test_images :
2011-10-13 18:04:12 +00:00
from . models import ImageFile , OptionalImageFile
2013-10-22 10:21:07 +00:00
2011-06-13 13:23:49 +00:00
class ImageFileForm ( forms . ModelForm ) :
class Meta :
model = ImageFile
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-13 13:23:49 +00:00
class OptionalImageFileForm ( forms . ModelForm ) :
class Meta :
model = OptionalImageFile
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class ProductForm ( forms . ModelForm ) :
class Meta :
model = Product
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class PriceForm ( forms . ModelForm ) :
class Meta :
model = Price
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class BookForm ( forms . ModelForm ) :
class Meta :
2013-06-14 14:02:30 +00:00
model = Book
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class DerivedBookForm ( forms . ModelForm ) :
class Meta :
model = DerivedBook
2013-06-14 14:02:30 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class ExplicitPKForm ( forms . ModelForm ) :
class Meta :
model = ExplicitPK
fields = ( ' key ' , ' desc ' , )
class PostForm ( forms . ModelForm ) :
class Meta :
model = Post
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class DerivedPostForm ( forms . ModelForm ) :
class Meta :
model = DerivedPost
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
2013-06-10 10:22:40 +00:00
class CustomWriterForm ( forms . ModelForm ) :
2013-09-03 18:22:21 +00:00
name = forms . CharField ( required = False )
2011-06-10 14:08:51 +00:00
2013-09-03 18:22:21 +00:00
class Meta :
model = Writer
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class BaseCategoryForm ( forms . ModelForm ) :
class Meta :
model = Category
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class ArticleForm ( forms . ModelForm ) :
class Meta :
model = Article
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class RoykoForm ( forms . ModelForm ) :
class Meta :
2013-06-10 10:22:40 +00:00
model = Writer
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class ArticleStatusForm ( forms . ModelForm ) :
class Meta :
model = ArticleStatus
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class InventoryForm ( forms . ModelForm ) :
class Meta :
model = Inventory
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class SelectInventoryForm ( forms . Form ) :
items = forms . ModelMultipleChoiceField ( Inventory . objects . all ( ) , to_field_name = ' barcode ' )
2013-02-21 21:56:55 +00:00
2011-06-10 14:08:51 +00:00
class CustomFieldForExclusionForm ( forms . ModelForm ) :
class Meta :
model = CustomFieldForExclusionModel
fields = [ ' name ' , ' markup ' ]
2013-02-21 21:56:55 +00:00
2011-06-10 14:08:51 +00:00
class TextFileForm ( forms . ModelForm ) :
class Meta :
model = TextFile
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class BigIntForm ( forms . ModelForm ) :
class Meta :
model = BigInt
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class ModelFormWithMedia ( forms . ModelForm ) :
class Media :
js = ( ' /some/form/javascript ' , )
css = {
' all ' : ( ' /some/form/css ' , )
}
2013-10-22 10:21:07 +00:00
2011-06-10 14:08:51 +00:00
class Meta :
2012-12-08 19:58:59 +00:00
model = TextFile
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
2013-06-05 18:55:05 +00:00
class CustomErrorMessageForm ( forms . ModelForm ) :
name1 = forms . CharField ( error_messages = { ' invalid ' : ' Form custom error message. ' } )
class Meta :
2013-07-01 13:36:31 +00:00
fields = ' __all__ '
2013-06-05 18:55:05 +00:00
model = CustomErrorMessage
2011-06-10 14:08:51 +00:00
class ModelFormBaseTest ( TestCase ) :
def test_base_form ( self ) :
2012-08-14 21:38:35 +00:00
self . assertEqual ( list ( BaseCategoryForm . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' name ' , ' slug ' , ' url ' ] )
2014-03-14 14:18:08 +00:00
def test_no_model_class ( self ) :
class NoModelModelForm ( forms . ModelForm ) :
pass
self . assertRaises ( ValueError , NoModelModelForm )
def test_empty_fields_to_fields_for_model ( self ) :
"""
An argument of fields = ( ) to fields_for_model should return an empty dictionary
"""
field_dict = fields_for_model ( Person , fields = ( ) )
self . assertEqual ( len ( field_dict ) , 0 )
def test_empty_fields_on_modelform ( self ) :
"""
No fields on a ModelForm should actually result in no fields .
"""
class EmptyPersonForm ( forms . ModelForm ) :
class Meta :
model = Person
fields = ( )
form = EmptyPersonForm ( )
self . assertEqual ( len ( form . fields ) , 0 )
def test_empty_fields_to_construct_instance ( self ) :
"""
No fields should be set on a model instance if construct_instance receives fields = ( ) .
"""
form = modelform_factory ( Person , fields = " __all__ " ) ( { ' name ' : ' John Doe ' } )
self . assertTrue ( form . is_valid ( ) )
instance = construct_instance ( form , Person ( ) , fields = ( ) )
self . assertEqual ( instance . name , ' ' )
2014-06-03 03:36:59 +00:00
def test_blank_with_null_foreign_key_field ( self ) :
"""
#13776 -- ModelForm's with models having a FK set to null=False and
required = False should be valid .
"""
class FormForTestingIsValid ( forms . ModelForm ) :
class Meta :
model = Student
fields = ' __all__ '
def __init__ ( self , * args , * * kwargs ) :
super ( FormForTestingIsValid , self ) . __init__ ( * args , * * kwargs )
self . fields [ ' character ' ] . required = False
char = Character . objects . create ( username = ' user ' ,
last_action = datetime . datetime . today ( ) )
data = { ' study ' : ' Engineering ' }
data2 = { ' study ' : ' Engineering ' , ' character ' : char . pk }
# form is valid because required=False for field 'character'
f1 = FormForTestingIsValid ( data )
self . assertTrue ( f1 . is_valid ( ) )
f2 = FormForTestingIsValid ( data2 )
self . assertTrue ( f2 . is_valid ( ) )
obj = f2 . save ( )
self . assertEqual ( obj . character , char )
2013-02-21 21:56:55 +00:00
def test_missing_fields_attribute ( self ) :
2014-03-22 00:44:34 +00:00
message = (
" Creating a ModelForm without either the ' fields ' attribute "
" or the ' exclude ' attribute is prohibited; form "
" MissingFieldsForm needs updating. "
)
with self . assertRaisesMessage ( ImproperlyConfigured , message ) :
2013-02-21 21:56:55 +00:00
class MissingFieldsForm ( forms . ModelForm ) :
class Meta :
model = Category
2011-06-10 14:08:51 +00:00
def test_extra_fields ( self ) :
class ExtraFields ( BaseCategoryForm ) :
some_extra_field = forms . BooleanField ( )
2012-08-14 21:38:35 +00:00
self . assertEqual ( list ( ExtraFields . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' name ' , ' slug ' , ' url ' , ' some_extra_field ' ] )
2014-03-14 14:18:08 +00:00
def test_extra_field_model_form ( self ) :
try :
class ExtraPersonForm ( forms . ModelForm ) :
""" ModelForm with an extra field """
age = forms . IntegerField ( )
class Meta :
model = Person
fields = ( ' name ' , ' no-field ' )
except FieldError as e :
# Make sure the exception contains some reference to the
# field responsible for the problem.
2014-10-28 10:02:56 +00:00
self . assertIn ( ' no-field ' , e . args [ 0 ] )
2014-03-14 14:18:08 +00:00
else :
self . fail ( ' Invalid " no-field " field not caught ' )
def test_extra_declared_field_model_form ( self ) :
try :
class ExtraPersonForm ( forms . ModelForm ) :
""" ModelForm with an extra field """
age = forms . IntegerField ( )
class Meta :
model = Person
fields = ( ' name ' , ' age ' )
except FieldError :
self . fail ( ' Declarative field raised FieldError incorrectly ' )
def test_extra_field_modelform_factory ( self ) :
self . assertRaises ( FieldError , modelform_factory ,
Person , fields = [ ' no-field ' , ' name ' ] )
2011-06-10 14:08:51 +00:00
def test_replace_field ( self ) :
class ReplaceField ( forms . ModelForm ) :
url = forms . BooleanField ( )
class Meta :
model = Category
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2013-05-21 09:42:15 +00:00
self . assertIsInstance ( ReplaceField . base_fields [ ' url ' ] ,
2013-11-02 22:50:35 +00:00
forms . fields . BooleanField )
2013-02-21 21:56:55 +00: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 09:42:15 +00:00
self . assertIsInstance ( ReplaceField . base_fields [ ' url ' ] ,
2013-11-02 22:50:35 +00:00
forms . fields . BooleanField )
2013-02-21 21:56:55 +00: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-02 21:02:56 +00:00
fields = [ ] # url will still appear, since it is explicit above
2011-06-10 14:08:51 +00:00
2013-05-21 09:42:15 +00:00
self . assertIsInstance ( ReplaceField . base_fields [ ' url ' ] ,
2013-11-02 22:50:35 +00:00
forms . fields . BooleanField )
2011-06-10 14:08:51 +00:00
def test_override_field ( self ) :
2013-06-10 10:22:40 +00:00
class WriterForm ( forms . ModelForm ) :
2011-06-10 14:08:51 +00:00
book = forms . CharField ( required = False )
class Meta :
2013-06-10 10:22:40 +00:00
model = Writer
2013-02-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
2013-06-10 10:22:40 +00:00
wf = WriterForm ( { ' name ' : ' Richard Lockridge ' } )
2011-06-10 14:08:51 +00:00
self . assertTrue ( wf . is_valid ( ) )
2013-04-07 16:41:35 +00: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-02 21:02:56 +00:00
fields = ( ' url ' ) # note the missing comma
2013-04-07 16:41:35 +00:00
2011-06-10 14:08:51 +00:00
def test_exclude_fields ( self ) :
class ExcludeFields ( forms . ModelForm ) :
class Meta :
model = Category
exclude = [ ' url ' ]
2012-08-14 21:38:35 +00:00
self . assertEqual ( list ( ExcludeFields . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' name ' , ' slug ' ] )
2013-04-07 16:41:35 +00: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-02 21:02:56 +00:00
exclude = ( ' url ' ) # note the missing comma
2013-04-07 16:41:35 +00:00
2014-03-14 14:18:08 +00:00
def test_exclude_and_validation ( self ) :
# 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.
class PriceFormWithoutQuantity ( forms . ModelForm ) :
class Meta :
model = Price
exclude = ( ' quantity ' , )
form = PriceFormWithoutQuantity ( { ' price ' : ' 6.00 ' } )
self . assertTrue ( form . is_valid ( ) )
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 PriceFormWithoutQuantity ( forms . ModelForm ) :
class Meta :
model = Price
fields = ( ' price ' , )
form = PriceFormWithoutQuantity ( { ' price ' : ' 6.00 ' } )
self . assertTrue ( form . is_valid ( ) )
# 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 . assertIsNone ( form . instance . quantity )
self . assertIsNone ( form . instance . pk )
2011-06-10 14:08:51 +00: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-14 21:38:35 +00:00
self . assertEqual ( list ( ConfusedForm . base_fields ) ,
2011-06-10 14:08:51 +00: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-21 21:56:55 +00:00
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
# MixModelForm is now an Article-related thing, because MixModelForm.Meta
# overrides BaseCategoryForm.Meta.
self . assertEqual (
2012-08-14 21:38:35 +00:00
list ( MixModelForm . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' headline ' , ' slug ' , ' pub_date ' , ' writer ' , ' article ' , ' categories ' , ' status ' ]
)
def test_article_form ( self ) :
self . assertEqual (
2012-08-14 21:38:35 +00:00
list ( ArticleForm . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' headline ' , ' slug ' , ' pub_date ' , ' writer ' , ' article ' , ' categories ' , ' status ' ]
)
def test_bad_form ( self ) :
2013-11-02 21:02:56 +00:00
# First class with a Meta class wins...
2011-06-10 14:08:51 +00:00
class BadForm ( ArticleForm , BaseCategoryForm ) :
pass
self . assertEqual (
2012-08-14 21:38:35 +00:00
list ( BadForm . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' headline ' , ' slug ' , ' pub_date ' , ' writer ' , ' article ' , ' categories ' , ' status ' ]
)
2013-02-23 17:29:56 +00: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 12:31:38 +00:00
InvalidModelForm ( )
2013-02-23 17:29:56 +00:00
# Even if you provide a model instance
with self . assertRaises ( ValueError ) :
2013-10-19 12:31:38 +00:00
InvalidModelForm ( instance = Category )
2013-02-23 17:29:56 +00:00
2011-06-10 14:08:51 +00: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-14 21:38:35 +00:00
self . assertEqual ( list ( SubCategoryForm . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' name ' , ' slug ' , ' url ' ] )
def test_subclassmeta_form ( self ) :
class SomeCategoryForm ( forms . ModelForm ) :
2013-09-03 18:22:21 +00:00
checkbox = forms . BooleanField ( )
2011-06-10 14:08:51 +00:00
2013-09-03 18:22:21 +00:00
class Meta :
model = Category
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
class SubclassMeta ( SomeCategoryForm ) :
""" We can also subclass the Meta inner class to change the fields
list .
"""
class Meta ( SomeCategoryForm . Meta ) :
exclude = [ ' url ' ]
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2011-06-10 14:08:51 +00: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 09:02:43 +00:00
)
2011-06-10 14:08:51 +00:00
def test_orderfields_form ( self ) :
class OrderFields ( forms . ModelForm ) :
class Meta :
model = Category
fields = [ ' url ' , ' name ' ]
2012-08-14 21:38:35 +00:00
self . assertEqual ( list ( OrderFields . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' url ' , ' name ' ] )
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2011-06-10 14:08:51 +00: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 09:02:43 +00:00
)
2011-06-10 14:08:51 +00:00
def test_orderfields2_form ( self ) :
class OrderFields2 ( forms . ModelForm ) :
class Meta :
model = Category
fields = [ ' slug ' , ' url ' , ' name ' ]
exclude = [ ' url ' ]
2012-08-14 21:38:35 +00:00
self . assertEqual ( list ( OrderFields2 . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' slug ' , ' name ' ] )
2014-03-04 20:06:30 +00:00
class FieldOverridesByFormMetaForm ( forms . ModelForm ) :
2011-06-10 14:08:51 +00:00
class Meta :
model = Category
fields = [ ' name ' , ' url ' , ' slug ' ]
widgets = {
' name ' : forms . Textarea ,
' url ' : forms . TextInput ( attrs = { ' class ' : ' url ' } )
}
2013-04-03 19:51:37 +00: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! "
)
}
}
2015-02-06 21:19:23 +00:00
field_classes = {
' url ' : forms . URLField ,
}
2011-06-10 14:08:51 +00:00
2014-03-04 20:06:30 +00:00
class TestFieldOverridesByFormMeta ( TestCase ) :
2013-04-03 19:51:37 +00:00
def test_widget_overrides ( self ) :
2014-03-04 20:06:30 +00:00
form = FieldOverridesByFormMetaForm ( )
2013-04-03 19:51:37 +00:00
self . assertHTMLEqual (
str ( form [ ' name ' ] ) ,
2014-03-04 14:12:13 +00:00
' <textarea id= " id_name " rows= " 10 " cols= " 40 " name= " name " maxlength= " 20 " ></textarea> ' ,
2013-04-03 19:51:37 +00:00
)
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 14:08:51 +00:00
2013-04-03 19:51:37 +00:00
def test_label_overrides ( self ) :
2014-03-04 20:06:30 +00:00
form = FieldOverridesByFormMetaForm ( )
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2013-04-03 19:51:37 +00:00
str ( form [ ' name ' ] . label_tag ( ) ) ,
' <label for= " id_name " >Title:</label> ' ,
2011-06-10 14:08:51 +00:00
)
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2013-04-03 19:51:37 +00:00
str ( form [ ' url ' ] . label_tag ( ) ) ,
' <label for= " id_url " >The URL:</label> ' ,
2011-06-10 14:08:51 +00:00
)
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2013-04-03 19:51:37 +00:00
str ( form [ ' slug ' ] . label_tag ( ) ) ,
' <label for= " id_slug " >Slug:</label> ' ,
)
def test_help_text_overrides ( self ) :
2014-03-04 20:06:30 +00:00
form = FieldOverridesByFormMetaForm ( )
2013-04-03 19:51:37 +00:00
self . assertEqual (
form [ ' slug ' ] . help_text ,
' Watch out! Letters, numbers, underscores and hyphens only. ' ,
2011-06-10 14:08:51 +00:00
)
2010-02-22 23:06:09 +00:00
2013-04-03 19:51:37 +00:00
def test_error_messages_overrides ( self ) :
2014-03-04 20:06:30 +00:00
form = FieldOverridesByFormMetaForm ( data = {
2013-04-03 19:51:37 +00:00
' name ' : ' Category ' ,
2015-02-06 21:19:23 +00:00
' url ' : ' http://www.example.com/category/ ' ,
2013-04-03 19:51:37 +00:00
' 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 } )
2015-02-06 21:19:23 +00:00
def test_field_type_overrides ( self ) :
form = FieldOverridesByFormMetaForm ( )
self . assertIs ( Category . _meta . get_field ( ' url ' ) . __class__ , models . CharField )
self . assertIsInstance ( form . fields [ ' url ' ] , forms . URLField )
2010-02-22 23:06:09 +00:00
2010-02-25 17:18:27 +00:00
class IncompleteCategoryFormWithFields ( forms . ModelForm ) :
2010-02-22 23:06:09 +00: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-02 22:50:35 +00:00
2010-02-25 17:18:27 +00: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-22 23:06:09 +00:00
class ValidationTest ( TestCase ) :
2010-02-25 17:18:27 +00: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-22 23:06:09 +00:00
assert form . is_valid ( )
2010-03-18 02:03:07 +00:00
def test_notrequired_overrides_notblank ( self ) :
2013-06-10 10:22:40 +00:00
form = CustomWriterForm ( { } )
2010-03-18 02:03:07 +00:00
assert form . is_valid ( )
2011-06-10 14:08:51 +00:00
2010-03-16 19:32:11 +00:00
class UniqueTest ( TestCase ) :
2014-03-14 14:18:08 +00:00
"""
unique / unique_together validation .
"""
2010-03-16 19:32:11 +00:00
def setUp ( self ) :
2013-06-10 10:22:40 +00:00
self . writer = Writer . objects . create ( name = ' Mike Royko ' )
2010-03-16 19:32:11 +00: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-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' slug ' ] , [ ' Product with this Slug already exists. ' ] )
2010-03-16 19:32:11 +00: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-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' __all__ ' ] , [ ' Price with this Price and Quantity already exists. ' ] )
2010-03-16 19:32:11 +00:00
2014-03-14 14:18:08 +00:00
def test_multiple_field_unique_together ( self ) :
"""
When the same field is involved in multiple unique_together
constraints , we need to make sure we don ' t remove the data for it
before doing all the validation checking ( not just failing after
the first one ) .
"""
class TripleForm ( forms . ModelForm ) :
class Meta :
model = Triple
fields = ' __all__ '
Triple . objects . create ( left = 1 , middle = 2 , right = 3 )
form = TripleForm ( { ' left ' : ' 1 ' , ' middle ' : ' 2 ' , ' right ' : ' 3 ' } )
self . assertFalse ( form . is_valid ( ) )
form = TripleForm ( { ' left ' : ' 1 ' , ' middle ' : ' 3 ' , ' right ' : ' 1 ' } )
self . assertTrue ( form . is_valid ( ) )
2014-05-07 20:03:10 +00:00
@skipUnlessDBFeature ( ' supports_nullable_unique_constraints ' )
2010-03-16 19:32:11 +00:00
def test_unique_null ( self ) :
title = ' I May Be Wrong But I Doubt It '
2013-06-10 10:22:40 +00:00
form = BookForm ( { ' title ' : title , ' author ' : self . writer . pk } )
2010-03-16 19:32:11 +00:00
self . assertTrue ( form . is_valid ( ) )
form . save ( )
2013-06-10 10:22:40 +00:00
form = BookForm ( { ' title ' : title , ' author ' : self . writer . pk } )
2010-03-16 19:32:11 +00:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' __all__ ' ] , [ ' Book with this Title and Author already exists. ' ] )
2013-06-10 10:22:40 +00:00
form = BookForm ( { ' title ' : title } )
2010-03-16 19:32:11 +00:00
self . assertTrue ( form . is_valid ( ) )
form . save ( )
2013-06-10 10:22:40 +00:00
form = BookForm ( { ' title ' : title } )
2010-03-16 19:32:11 +00:00
self . assertTrue ( form . is_valid ( ) )
def test_inherited_unique ( self ) :
2013-06-10 10:22:40 +00: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-16 19:32:11 +00:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2013-06-10 10:22:40 +00:00
self . assertEqual ( form . errors [ ' special_id ' ] , [ ' Book with this Special id already exists. ' ] )
2010-03-16 19:32:11 +00:00
def test_inherited_unique_together ( self ) :
title = ' Boss '
2013-06-10 10:22:40 +00:00
form = BookForm ( { ' title ' : title , ' author ' : self . writer . pk } )
2010-03-16 19:32:11 +00:00
self . assertTrue ( form . is_valid ( ) )
form . save ( )
2013-06-10 10:22:40 +00:00
form = DerivedBookForm ( { ' title ' : title , ' author ' : self . writer . pk , ' isbn ' : ' 12345 ' } )
2010-03-16 19:32:11 +00:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' __all__ ' ] , [ ' Book with this Title and Author already exists. ' ] )
2010-03-16 19:32:11 +00:00
def test_abstract_inherited_unique ( self ) :
title = ' Boss '
isbn = ' 12345 '
2013-10-19 12:31:38 +00:00
DerivedBook . objects . create ( title = title , author = self . writer , isbn = isbn )
2013-06-10 10:22:40 +00:00
form = DerivedBookForm ( { ' title ' : ' Other ' , ' author ' : self . writer . pk , ' isbn ' : isbn } )
2010-03-16 19:32:11 +00:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' isbn ' ] , [ ' Derived book with this Isbn already exists. ' ] )
2010-03-16 19:32:11 +00:00
def test_abstract_inherited_unique_together ( self ) :
title = ' Boss '
isbn = ' 12345 '
2013-10-19 12:31:38 +00:00
DerivedBook . objects . create ( title = title , author = self . writer , isbn = isbn )
2011-06-10 14:08:51 +00:00
form = DerivedBookForm ( {
2013-10-19 23:33:10 +00:00
' title ' : ' Other ' ,
' author ' : self . writer . pk ,
' isbn ' : ' 9876 ' ,
' suffix1 ' : ' 0 ' ,
' suffix2 ' : ' 0 '
} )
2010-03-16 19:32:11 +00:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2011-06-10 14:08:51 +00:00
self . assertEqual ( form . errors [ ' __all__ ' ] ,
2012-06-07 16:08:47 +00:00
[ ' Derived book with this Suffix1 and Suffix2 already exists. ' ] )
2010-03-16 19:32:11 +00:00
def test_explicitpk_unspecified ( self ) :
""" Test for primary_key being in the form and failing validation. """
2013-10-14 19:13:14 +00:00
form = ExplicitPKForm ( { ' key ' : ' ' , ' desc ' : ' ' } )
2010-03-16 19:32:11 +00:00
self . assertFalse ( form . is_valid ( ) )
def test_explicitpk_unique ( self ) :
""" Ensure keys and blank character strings are tested for uniqueness. """
2012-06-07 16:08:47 +00:00
form = ExplicitPKForm ( { ' key ' : ' key1 ' , ' desc ' : ' ' } )
2010-03-16 19:32:11 +00:00
self . assertTrue ( form . is_valid ( ) )
form . save ( )
2012-06-07 16:08:47 +00:00
form = ExplicitPKForm ( { ' key ' : ' key1 ' , ' desc ' : ' ' } )
2010-03-16 19:32:11 +00:00
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 3 )
2012-06-07 16:08:47 +00: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-16 19:32:11 +00: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-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' title ' ] , [ ' Title must be unique for Posted date. ' ] )
2010-03-16 19:32:11 +00: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-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' slug ' ] , [ ' Slug must be unique for Posted year. ' ] )
2010-03-16 19:32:11 +00:00
form = PostForm ( { ' subtitle ' : " Finally " , ' posted ' : ' 2008-09-30 ' } )
self . assertFalse ( form . is_valid ( ) )
2012-06-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' subtitle ' ] , [ ' Subtitle must be unique for Posted month. ' ] )
2010-03-16 19:32:11 +00: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 07:07:28 +00:00
form = PostForm ( { ' title ' : " Django 1.0 is released " } )
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( len ( form . errors ) , 1 )
2012-06-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' posted ' ] , [ ' This field is required. ' ] )
2010-03-16 19:32:11 +00:00
2013-05-28 13:56:14 +00:00
def test_unique_for_date_in_exclude ( self ) :
2014-03-14 08:44:56 +00:00
"""
If the date for unique_for_ * constraints is excluded from the
2013-05-28 13:56:14 +00:00
ModelForm ( in this case ' posted ' has editable = False , then the
2014-03-14 08:44:56 +00:00
constraint should be ignored .
"""
class DateTimePostForm ( forms . ModelForm ) :
class Meta :
model = DateTimePost
fields = ' __all__ '
2013-10-19 12:31:38 +00:00
DateTimePost . objects . create ( title = " Django 1.0 is released " ,
2013-05-28 13:56:14 +00: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-16 19:32:11 +00: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-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' title ' ] , [ ' Title must be unique for Posted date. ' ] )
2010-03-16 19:32:11 +00: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-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' slug ' ] , [ ' Slug must be unique for Posted year. ' ] )
2010-03-16 19:32:11 +00:00
form = DerivedPostForm ( { ' subtitle ' : " Finally " , ' posted ' : ' 2008-09-30 ' } )
self . assertFalse ( form . is_valid ( ) )
2012-06-07 16:08:47 +00:00
self . assertEqual ( form . errors [ ' subtitle ' ] , [ ' Subtitle must be unique for Posted month. ' ] )
2010-03-16 19:32:11 +00: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 13:26:39 +00:00
def test_unique_for_date_with_nullable_date ( self ) :
2014-03-14 08:44:56 +00:00
class FlexDatePostForm ( forms . ModelForm ) :
class Meta :
model = FlexibleDatePost
fields = ' __all__ '
2011-01-09 13:26:39 +00:00
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 14:08:51 +00:00
2014-02-03 18:31:27 +00: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-02 22:50:35 +00:00
2012-11-04 23:42:17 +00:00
class ModelToDictTests ( TestCase ) :
"""
Tests for forms . models . model_to_dict
"""
def test_model_to_dict_many_to_many ( self ) :
2013-10-23 10:09:29 +00:00
categories = [
2012-11-04 23:42:17 +00: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 10:22:40 +00:00
writer = Writer ( name = ' Test writer ' )
2012-11-04 23:42:17 +00: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-02 21:02:56 +00:00
# Ensure all many-to-many categories appear in model_to_dict
2012-11-04 23:42:17 +00:00
for c in categories :
self . assertIn ( c . pk , d [ ' categories ' ] )
2013-11-02 21:02:56 +00:00
# Ensure many-to-many relation appears as a list
2012-11-04 23:42:17 +00:00
self . assertIsInstance ( d [ ' categories ' ] , list )
2013-11-01 12:55:35 +00: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 )
2015-02-05 18:25:34 +00:00
# Ensure all many-to-many categories appear in model_to_dict
2013-11-01 12:55:35 +00:00
for c in categories :
self . assertIn ( c . pk , d [ ' categories ' ] )
2015-02-05 18:25:34 +00:00
# Ensure many-to-many relation appears as a list
2013-11-01 12:55:35 +00:00
self . assertIsInstance ( d [ ' categories ' ] , list )
2013-11-02 22:50:35 +00:00
2014-03-14 08:44:56 +00:00
class ModelFormBasicTests ( TestCase ) :
def create_basic_data ( self ) :
self . c1 = Category . objects . create (
name = " Entertainment " , slug = " entertainment " , url = " entertainment " )
self . c2 = Category . objects . create (
name = " It ' s a test " , slug = " its-test " , url = " test " )
self . c3 = Category . objects . create (
name = " Third test " , slug = " third-test " , url = " third " )
self . w_royko = Writer . objects . create ( name = ' Mike Royko ' )
self . w_woodward = Writer . objects . create ( name = ' Bob Woodward ' )
2011-06-10 14:08:51 +00:00
def test_base_form ( self ) :
self . assertEqual ( Category . objects . count ( ) , 0 )
f = BaseCategoryForm ( )
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2011-06-10 14:08:51 +00: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 09:02:43 +00:00
)
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2011-06-10 14:08:51 +00: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 09:02:43 +00:00
)
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2011-06-10 14:08:51 +00: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-01-31 20:36:11 +00:00
self . assertHTMLEqual (
2011-06-10 14:08:51 +00: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 09:02:43 +00:00
)
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
def test_initial_values ( self ) :
self . create_basic_data ( )
# Initial values can be provided for model forms
f = ArticleForm (
auto_id = False ,
initial = {
' headline ' : ' Your headline here ' ,
' categories ' : [ str ( self . c1 . id ) , str ( self . c2 . id ) ]
} )
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " value= " Your headline here " maxlength= " 50 " /></li>
< 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 >
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Mike Royko < / option >
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
< option value = " %s " selected = " selected " > Entertainment < / option >
< option value = " %s " selected = " selected " > It & #39;s a test</option>
< option value = " %s " > Third test < / option >
2014-03-21 23:07:13 +00:00
< / select > < / li >
2014-03-14 08:44:56 +00:00
< 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 >
< / select > < / li > ''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk))
# When the ModelForm is passed an instance, that instance's current values are
# inserted as 'initial' data in each Field.
f = RoykoForm ( auto_id = False , instance = self . w_royko )
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> ''' )
art = Article . objects . create (
headline = ' Test article ' ,
slug = ' test-article ' ,
pub_date = datetime . date ( 1988 , 1 , 4 ) ,
writer = self . w_royko ,
article = ' Hello. '
)
art_id_1 = art . id
f = ArticleForm ( auto_id = False , instance = art )
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " value= " Test article " maxlength= " 50 " /></li>
< 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 >
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " selected = " selected " > Mike Royko < / option >
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > Hello . < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
< option value = " %s " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
< option value = " %s " > Third test < / option >
2014-03-21 23:07:13 +00:00
< / select > < / li >
2014-03-14 08:44:56 +00:00
< 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 >
< / select > < / li > ''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk))
f = ArticleForm ( {
' headline ' : ' Test headline ' ,
' slug ' : ' test-headline ' ,
' pub_date ' : ' 1984-02-06 ' ,
' writer ' : six . text_type ( self . w_royko . pk ) ,
' article ' : ' Hello. '
} , instance = art )
self . assertEqual ( f . errors , { } )
self . assertTrue ( f . is_valid ( ) )
test_art = f . save ( )
self . assertEqual ( test_art . id , art_id_1 )
test_art = Article . objects . get ( id = art_id_1 )
self . assertEqual ( test_art . headline , ' Test headline ' )
2014-03-14 14:18:08 +00:00
def test_m2m_initial_callable ( self ) :
"""
Regression for #10349: A callable can be provided as the initial value for an m2m field
"""
self . maxDiff = 1200
self . create_basic_data ( )
# Set up a callable initial value
def formfield_for_dbfield ( db_field , * * kwargs ) :
if db_field . name == ' categories ' :
kwargs [ ' initial ' ] = lambda : Category . objects . all ( ) . order_by ( ' name ' ) [ : 2 ]
return db_field . formfield ( * * kwargs )
# Create a ModelForm, instantiate it, and check that the output is as expected
ModelForm = modelform_factory ( Article , fields = [ ' headline ' , ' categories ' ] ,
formfield_callback = formfield_for_dbfield )
form = ModelForm ( )
self . assertHTMLEqual ( form . as_ul ( ) , """ <li><label for= " id_headline " >Headline:</label> <input id= " id_headline " type= " text " name= " headline " maxlength= " 50 " /></li>
< li > < label for = " id_categories " > Categories : < / label > < select multiple = " multiple " name = " categories " id = " id_categories " >
< option value = " %d " selected = " selected " > Entertainment < / option >
< option value = " %d " selected = " selected " > It & 39 ; s a test < / option >
< option value = " %d " > Third test < / option >
2014-03-21 23:07:13 +00:00
< / select > < / li > """
2014-03-14 14:18:08 +00:00
% ( self . c1 . pk , self . c2 . pk , self . c3 . pk ) )
2014-03-14 08:44:56 +00:00
def test_basic_creation ( self ) :
2011-06-10 14:08:51 +00:00
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 ( )
2014-11-03 22:48:03 +00:00
# Testing whether the same object is returned from the
2011-06-10 14:08:51 +00:00
# ORM... not the fastest way...
2014-03-14 08:44:56 +00:00
self . assertEqual ( Category . objects . count ( ) , 1 )
2011-06-10 14:08:51 +00:00
self . assertEqual ( c1 , Category . objects . all ( ) [ 0 ] )
self . assertEqual ( c1 . name , " Entertainment " )
2014-03-14 08:44:56 +00:00
def test_save_commit_false ( self ) :
2011-06-10 14:08:51 +00:00
# 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 ' } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
c1 = f . save ( commit = False )
self . assertEqual ( c1 . name , " Third test " )
self . assertEqual ( Category . objects . count ( ) , 0 )
c1 . save ( )
self . assertEqual ( Category . objects . count ( ) , 1 )
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
def test_save_with_data_errors ( self ) :
2011-06-10 14:08:51 +00:00
# If you call save() with invalid data, you'll get a ValueError.
f = BaseCategoryForm ( { ' name ' : ' ' , ' slug ' : ' not a slug! ' , ' url ' : ' foo ' } )
2012-06-07 16:08:47 +00: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 12:17:02 +00:00
self . assertEqual ( f . cleaned_data , { ' url ' : ' foo ' } )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValueError ) :
f . save ( )
f = BaseCategoryForm ( { ' name ' : ' ' , ' slug ' : ' ' , ' url ' : ' foo ' } )
with self . assertRaises ( ValueError ) :
f . save ( )
2014-03-14 08:44:56 +00:00
def test_multi_fields ( self ) :
self . create_basic_data ( )
self . maxDiff = None
2011-06-10 14:08:51 +00:00
# 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 12:48:51 +00:00
self . assertHTMLEqual ( six . text_type ( f ) , ''' <tr><th>Headline:</th><td><input type= " text " name= " headline " maxlength= " 50 " /></td></tr>
2011-06-10 14:08:51 +00: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-21 18:09:08 +00:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 14:08:51 +00: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-21 18:09:08 +00:00
< option value = " %s " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
< option value = " %s " > Third test < / option >
2014-03-21 23:07:13 +00:00
< / select > < / td > < / tr >
2011-06-10 14:08:51 +00:00
< 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 >
2014-03-14 08:44:56 +00:00
< / select > < / td > < / tr > ''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk))
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
# Add some categories and test the many-to-many form output.
new_art = Article . objects . create (
article = " Hello. " , headline = " New headline " , slug = " new-headline " ,
pub_date = datetime . date ( 1988 , 1 , 4 ) , writer = self . w_royko )
new_art . categories . add ( Category . objects . get ( name = ' Entertainment ' ) )
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ " Entertainment " ] )
f = ArticleForm ( auto_id = False , instance = new_art )
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " value= " New headline " maxlength= " 50 " /></li>
< li > Slug : < input type = " text " name = " slug " value = " new-headline " maxlength = " 50 " / > < / li >
2011-06-10 14:08:51 +00:00
< li > Pub date : < input type = " text " name = " pub_date " value = " 1988-01-04 " / > < / li >
< li > Writer : < select name = " writer " >
< option value = " " > - - - - - - - - - < / option >
2011-08-21 18:09:08 +00:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " selected = " selected " > Mike Royko < / option >
2011-06-10 14:08:51 +00:00
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > Hello . < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
2014-03-14 08:44:56 +00:00
< option value = " %s " selected = " selected " > Entertainment < / option >
2011-08-21 18:09:08 +00:00
< option value = " %s " > It & #39;s a test</option>
< option value = " %s " > Third test < / option >
2014-03-21 23:07:13 +00:00
< / select > < / li >
2011-06-10 14:08:51 +00:00
< 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 >
2014-03-14 08:44:56 +00:00
< / select > < / li > ''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk))
def test_subset_fields ( self ) :
# 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!
class PartialArticleForm ( forms . ModelForm ) :
class Meta :
model = Article
fields = ( ' headline ' , ' pub_date ' )
f = PartialArticleForm ( auto_id = False )
self . assertHTMLEqual ( six . text_type ( f ) , ''' <tr><th>Headline:</th><td><input type= " text " name= " headline " maxlength= " 50 " /></td></tr>
< tr > < th > Pub date : < / th > < td > < input type = " text " name = " pub_date " / > < / td > < / tr > ''' )
2011-06-10 14:08:51 +00:00
# You can create a form over a subset of the available fields
# by specifying a 'fields' argument to form_for_instance.
2014-03-14 08:44:56 +00:00
class PartialArticleFormWithSlug ( forms . ModelForm ) :
class Meta :
model = Article
fields = ( ' headline ' , ' slug ' , ' pub_date ' )
w_royko = Writer . objects . create ( name = ' Mike Royko ' )
art = Article . objects . create (
article = " Hello. " , headline = " New headline " , slug = " new-headline " ,
pub_date = datetime . date ( 1988 , 1 , 4 ) , writer = w_royko )
2011-06-10 14:08:51 +00:00
f = PartialArticleFormWithSlug ( {
2013-10-19 23:33:10 +00:00
' headline ' : ' New headline ' ,
' slug ' : ' new-headline ' ,
' pub_date ' : ' 1988-01-04 '
2013-10-18 09:02:43 +00:00
} , auto_id = False , instance = art )
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " value= " New headline " maxlength= " 50 " /></li>
2011-06-10 14:08:51 +00: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 > ''' )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
new_art = f . save ( )
2014-03-14 08:44:56 +00:00
self . assertEqual ( new_art . id , art . id )
new_art = Article . objects . get ( id = art . id )
2012-06-07 16:08:47 +00:00
self . assertEqual ( new_art . headline , ' New headline ' )
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
def test_m2m_editing ( self ) :
self . create_basic_data ( )
form_data = {
2013-10-19 23:33:10 +00:00
' headline ' : ' New headline ' ,
' slug ' : ' new-headline ' ,
' pub_date ' : ' 1988-01-04 ' ,
2014-03-14 08:44:56 +00:00
' writer ' : six . text_type ( self . w_royko . pk ) ,
2013-10-19 23:33:10 +00:00
' article ' : ' Hello. ' ,
2014-03-14 08:44:56 +00:00
' categories ' : [ six . text_type ( self . c1 . id ) , six . text_type ( self . c2 . id ) ]
}
# Create a new article, with categories, via the form.
f = ArticleForm ( form_data )
2011-06-10 14:08:51 +00:00
new_art = f . save ( )
2014-03-14 08:44:56 +00:00
new_art = Article . objects . get ( id = new_art . id )
art_id_1 = new_art . id
2012-08-14 21:38:35 +00:00
self . assertQuerysetEqual ( new_art . categories . order_by ( ' name ' ) ,
2011-06-10 14:08:51 +00:00
[ " Entertainment " , " It ' s a test " ] )
# Now, submit form data with no categories. This deletes the existing categories.
2014-03-14 08:44:56 +00:00
form_data [ ' categories ' ] = [ ]
f = ArticleForm ( form_data , instance = new_art )
2011-06-10 14:08:51 +00:00
new_art = f . save ( )
2014-03-14 08:44:56 +00:00
self . assertEqual ( new_art . id , art_id_1 )
2011-06-10 14:08:51 +00:00
new_art = Article . objects . get ( id = art_id_1 )
2012-08-14 21:38:35 +00:00
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ ] )
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
# Create a new article, with no categories, via the form.
f = ArticleForm ( form_data )
2011-06-10 14:08:51 +00:00
new_art = f . save ( )
art_id_2 = new_art . id
2014-03-14 08:44:56 +00:00
self . assertNotIn ( art_id_2 , ( None , art_id_1 ) )
2011-06-10 14:08:51 +00:00
new_art = Article . objects . get ( id = art_id_2 )
2012-08-14 21:38:35 +00:00
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ ] )
2011-06-10 14:08:51 +00: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.
2014-03-14 08:44:56 +00:00
form_data [ ' categories ' ] = [ six . text_type ( self . c1 . id ) , six . text_type ( self . c2 . id ) ]
f = ArticleForm ( form_data )
2011-06-10 14:08:51 +00:00
new_art = f . save ( commit = False )
# Manually save the instance
new_art . save ( )
2014-03-14 08:44:56 +00:00
art_id_3 = new_art . id
self . assertNotIn ( art_id_3 , ( None , art_id_1 , art_id_2 ) )
2011-06-10 14:08:51 +00:00
# The instance doesn't have m2m data yet
2014-03-14 08:44:56 +00:00
new_art = Article . objects . get ( id = art_id_3 )
2012-08-14 21:38:35 +00:00
self . assertQuerysetEqual ( new_art . categories . all ( ) , [ ] )
2011-06-10 14:08:51 +00:00
# Save the m2m data on the form
f . save_m2m ( )
2014-03-14 08:44:56 +00:00
self . assertQuerysetEqual ( new_art . categories . order_by ( ' name ' ) ,
[ " Entertainment " , " It ' s a test " ] )
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
def test_custom_form_fields ( self ) :
2011-06-10 14:08:51 +00: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.
2014-03-14 08:44:56 +00:00
class ShortCategory ( forms . ModelForm ) :
name = forms . CharField ( max_length = 5 )
slug = forms . CharField ( max_length = 5 )
url = forms . CharField ( max_length = 3 )
class Meta :
model = Category
fields = ' __all__ '
cat = Category . objects . create ( name = ' Third test ' )
2011-06-10 14:08:51 +00:00
form = ShortCategory ( { ' name ' : ' Third ' , ' slug ' : ' third ' , ' url ' : ' 3rd ' } , instance = cat )
self . assertEqual ( form . save ( ) . name , ' Third ' )
2014-03-14 08:44:56 +00:00
self . assertEqual ( Category . objects . get ( id = cat . id ) . name , ' Third ' )
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
def test_runtime_choicefield_populated ( self ) :
2014-03-20 17:30:41 +00:00
self . maxDiff = None
2011-06-10 14:08:51 +00:00
# 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.
2014-03-14 08:44:56 +00:00
self . create_basic_data ( )
2011-06-10 14:08:51 +00:00
f = ArticleForm ( auto_id = False )
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " maxlength= " 50 " /></li>
2011-06-10 14:08:51 +00: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-21 18:09:08 +00:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 14:08:51 +00:00
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
2011-08-21 18:09:08 +00:00
< option value = " %s " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
2014-03-14 08:44:56 +00:00
< option value = " %s " > Third test < / option >
2014-03-21 23:07:13 +00:00
< / select > < / li >
2011-06-10 14:08:51 +00:00
< 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 >
2014-03-14 08:44:56 +00:00
< / select > < / li > ''' % (self.w_woodward.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk))
2011-06-10 14:08:51 +00:00
c4 = Category . objects . create ( name = ' Fourth ' , url = ' 4th ' )
2013-06-10 10:22:40 +00:00
w_bernstein = Writer . objects . create ( name = ' Carl Bernstein ' )
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual ( f . as_ul ( ) , ''' <li>Headline: <input type= " text " name= " headline " maxlength= " 50 " /></li>
2011-06-10 14:08:51 +00: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-21 18:09:08 +00:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Carl Bernstein < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 14:08:51 +00:00
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
2011-08-21 18:09:08 +00:00
< option value = " %s " > Entertainment < / option >
< option value = " %s " > It & #39;s a test</option>
2014-03-14 08:44:56 +00:00
< option value = " %s " > Third test < / option >
2011-08-21 18:09:08 +00:00
< option value = " %s " > Fourth < / option >
2014-03-21 23:07:13 +00:00
< / select > < / li >
2011-06-10 14:08:51 +00:00
< 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 >
2014-03-14 08:44:56 +00:00
< / select > < / li > ''' % (self.w_woodward.pk, w_bernstein.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk, c4.pk))
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
class ModelChoiceFieldTests ( TestCase ) :
def setUp ( self ) :
2014-03-14 08:44:56 +00:00
self . c1 = Category . objects . create (
name = " Entertainment " , slug = " entertainment " , url = " entertainment " )
self . c2 = Category . objects . create (
name = " It ' s a test " , slug = " its-test " , url = " test " )
self . c3 = Category . objects . create (
name = " Third " , slug = " third-test " , url = " third " )
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
# ModelChoiceField ############################################################
def test_modelchoicefield ( self ) :
2011-06-10 14:08:51 +00:00
f = forms . ModelChoiceField ( Category . objects . all ( ) )
self . assertEqual ( list ( f . choices ) , [
2012-06-07 16:08:47 +00:00
( ' ' , ' --------- ' ) ,
2014-03-14 08:44:56 +00:00
( self . c1 . pk , ' Entertainment ' ) ,
( self . c2 . pk , " It ' s a test " ) ,
( self . c3 . pk , ' Third ' ) ] )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
f . clean ( ' ' )
with self . assertRaises ( ValidationError ) :
f . clean ( None )
with self . assertRaises ( ValidationError ) :
f . clean ( 0 )
2014-07-26 09:06:30 +00:00
# Invalid types that require TypeError to be caught (#22808).
with self . assertRaises ( ValidationError ) :
f . clean ( [ [ ' fail ' ] ] )
with self . assertRaises ( ValidationError ) :
f . clean ( [ { ' foo ' : ' bar ' } ] )
2014-03-14 08:44:56 +00:00
self . assertEqual ( f . clean ( self . c2 . id ) . name , " It ' s a test " )
self . assertEqual ( f . clean ( self . c3 . id ) . name , ' Third ' )
2011-06-10 14:08:51 +00:00
# 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.
2014-03-14 08:44:56 +00:00
c4 = Category . objects . create ( name = ' Fourth ' , url = ' 4th ' )
self . assertEqual ( f . clean ( c4 . id ) . name , ' Fourth ' )
2011-06-10 14:08:51 +00:00
# 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.
2014-03-14 08:44:56 +00:00
Category . objects . get ( url = ' 4th ' ) . delete ( )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
2014-03-14 08:44:56 +00:00
f . clean ( c4 . id )
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
def test_modelchoicefield_choices ( self ) :
f = forms . ModelChoiceField ( Category . objects . filter ( pk = self . c1 . id ) , required = False )
self . assertIsNone ( f . clean ( ' ' ) )
self . assertEqual ( f . clean ( str ( self . c1 . id ) ) . name , " Entertainment " )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
f . clean ( ' 100 ' )
2014-03-20 17:30:41 +00:00
2014-03-14 14:18:08 +00:00
# len can be called on choices
self . assertEqual ( len ( f . choices ) , 2 )
2014-03-20 17:30:41 +00:00
2011-06-10 14:08:51 +00:00
# queryset can be changed after the field is created.
2014-03-14 08:44:56 +00:00
f . queryset = Category . objects . exclude ( name = ' Third ' )
2011-06-10 14:08:51 +00:00
self . assertEqual ( list ( f . choices ) , [
2012-06-07 16:08:47 +00:00
( ' ' , ' --------- ' ) ,
2014-03-14 08:44:56 +00:00
( self . c1 . pk , ' Entertainment ' ) ,
( self . c2 . pk , " It ' s a test " ) ] )
self . assertEqual ( f . clean ( self . c2 . id ) . name , " It ' s a test " )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
2014-03-14 08:44:56 +00:00
f . clean ( self . c3 . id )
2011-06-10 14:08:51 +00:00
# check that we can safely iterate choices repeatedly
gen_one = list ( f . choices )
gen_two = f . choices
2014-03-14 08:44:56 +00:00
self . assertEqual ( gen_one [ 2 ] , ( self . c2 . pk , " It ' s a test " ) )
2011-06-10 14:08:51 +00:00
self . assertEqual ( list ( gen_two ) , [
2012-06-07 16:08:47 +00:00
( ' ' , ' --------- ' ) ,
2014-03-14 08:44:56 +00:00
( self . c1 . pk , ' Entertainment ' ) ,
( self . c2 . pk , " It ' s a test " ) ] )
2011-06-10 14:08:51 +00: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-07 16:08:47 +00:00
( ' ' , ' --------- ' ) ,
2014-03-14 08:44:56 +00:00
( self . c1 . pk , ' category Entertainment ' ) ,
( self . c2 . pk , " category It ' s a test " ) ,
( self . c3 . pk , ' category Third ' ) ] )
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
def test_modelchoicefield_11183 ( self ) :
"""
Regression test for ticket #11183.
"""
class ModelChoiceForm ( forms . Form ) :
category = forms . ModelChoiceField ( Category . objects . all ( ) )
form1 = ModelChoiceForm ( )
field1 = form1 . fields [ ' category ' ]
# To allow the widget to change the queryset of field1.widget.choices correctly,
# without affecting other forms, the following must hold:
2014-10-28 10:02:56 +00:00
self . assertIsNot ( field1 , ModelChoiceForm . base_fields [ ' category ' ] )
self . assertIs ( field1 . widget . choices . field , field1 )
2014-03-14 14:18:08 +00:00
2014-06-16 07:47:45 +00:00
def test_modelchoicefield_22745 ( self ) :
"""
#22745 -- Make sure that ModelChoiceField with RadioSelect widget
doesn ' t produce unnecessary db queries when accessing its BoundField ' s
attrs .
"""
class ModelChoiceForm ( forms . Form ) :
category = forms . ModelChoiceField ( Category . objects . all ( ) , widget = forms . RadioSelect )
form = ModelChoiceForm ( )
field = form [ ' category ' ] # BoundField
template = Template ( ' {{ field.name }} {{ field }} {{ field.help_text }} ' )
with self . assertNumQueries ( 1 ) :
template . render ( Context ( { ' field ' : field } ) )
2014-03-14 14:18:08 +00:00
class ModelMultipleChoiceFieldTests ( TestCase ) :
def setUp ( self ) :
self . c1 = Category . objects . create (
name = " Entertainment " , slug = " entertainment " , url = " entertainment " )
self . c2 = Category . objects . create (
name = " It ' s a test " , slug = " its-test " , url = " test " )
self . c3 = Category . objects . create (
name = " Third " , slug = " third-test " , url = " third " )
def test_model_multiple_choice_field ( self ) :
2011-06-10 14:08:51 +00:00
f = forms . ModelMultipleChoiceField ( Category . objects . all ( ) )
self . assertEqual ( list ( f . choices ) , [
2014-03-14 08:44:56 +00:00
( self . c1 . pk , ' Entertainment ' ) ,
( self . c2 . pk , " It ' s a test " ) ,
( self . c3 . pk , ' Third ' ) ] )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
f . clean ( None )
with self . assertRaises ( ValidationError ) :
f . clean ( [ ] )
2014-03-14 08:44:56 +00:00
self . assertQuerysetEqual ( f . clean ( [ self . c1 . id ] ) , [ " Entertainment " ] )
self . assertQuerysetEqual ( f . clean ( [ self . c2 . id ] ) , [ " It ' s a test " ] )
self . assertQuerysetEqual ( f . clean ( [ str ( self . c1 . id ) ] ) , [ " Entertainment " ] )
self . assertQuerysetEqual ( f . clean ( [ str ( self . c1 . id ) , str ( self . c2 . id ) ] ) ,
[ " Entertainment " , " It ' s a test " ] , ordered = False )
self . assertQuerysetEqual ( f . clean ( [ self . c1 . id , str ( self . c2 . id ) ] ) ,
[ " Entertainment " , " It ' s a test " ] , ordered = False )
self . assertQuerysetEqual ( f . clean ( ( self . c1 . id , str ( self . c2 . id ) ) ) ,
[ " Entertainment " , " It ' s a test " ] , ordered = False )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
f . clean ( [ ' 100 ' ] )
with self . assertRaises ( ValidationError ) :
f . clean ( ' hello ' )
with self . assertRaises ( ValidationError ) :
f . clean ( [ ' fail ' ] )
2014-07-26 09:06:30 +00:00
# Invalid types that require TypeError to be caught (#22808).
with self . assertRaises ( ValidationError ) :
f . clean ( [ [ ' fail ' ] ] )
with self . assertRaises ( ValidationError ) :
f . clean ( [ { ' foo ' : ' bar ' } ] )
2011-06-10 14:08:51 +00:00
# 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 02:23:03 +00: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
2014-03-14 08:44:56 +00:00
# a number that will not conflict.
2012-11-05 02:23:03 +00:00
c6 = Category . objects . create ( id = 1006 , name = ' Sixth ' , url = ' 6th ' )
2012-08-14 21:38:35 +00:00
self . assertQuerysetEqual ( f . clean ( [ c6 . id ] ) , [ " Sixth " ] )
2011-06-10 14:08:51 +00: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 ] )
2014-03-14 14:18:08 +00:00
def test_model_multiple_choice_required_false ( self ) :
2011-06-10 14:08:51 +00:00
f = forms . ModelMultipleChoiceField ( Category . objects . all ( ) , required = False )
2012-10-03 16:50:12 +00:00
self . assertIsInstance ( f . clean ( [ ] ) , EmptyQuerySet )
self . assertIsInstance ( f . clean ( ( ) ) , EmptyQuerySet )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
2013-11-03 13:16:48 +00:00
f . clean ( [ ' 0 ' ] )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
2014-03-14 08:44:56 +00:00
f . clean ( [ str ( self . c3 . id ) , ' 0 ' ] )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
2014-03-14 08:44:56 +00:00
f . clean ( [ str ( self . c1 . id ) , ' 0 ' ] )
2011-06-10 14:08:51 +00:00
# queryset can be changed after the field is created.
2014-03-14 08:44:56 +00:00
f . queryset = Category . objects . exclude ( name = ' Third ' )
2011-06-10 14:08:51 +00:00
self . assertEqual ( list ( f . choices ) , [
2014-03-14 08:44:56 +00:00
( self . c1 . pk , ' Entertainment ' ) ,
( self . c2 . pk , " It ' s a test " ) ] )
self . assertQuerysetEqual ( f . clean ( [ self . c2 . id ] ) , [ " It ' s a test " ] )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
2014-03-14 08:44:56 +00:00
f . clean ( [ self . c3 . id ] )
2011-06-10 14:08:51 +00:00
with self . assertRaises ( ValidationError ) :
2014-03-14 08:44:56 +00:00
f . clean ( [ str ( self . c2 . id ) , str ( self . c3 . id ) ] )
2011-06-10 14:08:51 +00:00
f . queryset = Category . objects . all ( )
f . label_from_instance = lambda obj : " multicategory " + str ( obj )
self . assertEqual ( list ( f . choices ) , [
2014-03-14 08:44:56 +00:00
( self . c1 . pk , ' multicategory Entertainment ' ) ,
( self . c2 . pk , " multicategory It ' s a test " ) ,
( self . c3 . pk , ' multicategory Third ' ) ] )
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
def test_model_multiple_choice_number_of_queries ( self ) :
"""
Test that ModelMultipleChoiceField does O ( 1 ) queries instead of
O ( n ) ( #10156).
"""
persons = [ Writer . objects . create ( name = " Person %s " % i ) for i in range ( 30 ) ]
f = forms . ModelMultipleChoiceField ( queryset = Writer . objects . all ( ) )
self . assertNumQueries ( 1 , f . clean , [ p . pk for p in persons [ 1 : 11 : 2 ] ] )
def test_model_multiple_choice_run_validators ( self ) :
"""
Test that ModelMultipleChoiceField run given validators ( #14144).
"""
for i in range ( 30 ) :
Writer . objects . create ( name = " Person %s " % i )
self . _validator_run = False
def my_validator ( value ) :
self . _validator_run = True
f = forms . ModelMultipleChoiceField ( queryset = Writer . objects . all ( ) ,
validators = [ my_validator ] )
f . clean ( [ p . pk for p in Writer . objects . all ( ) [ 8 : 9 ] ] )
self . assertTrue ( self . _validator_run )
def test_model_multiple_choice_show_hidden_initial ( self ) :
"""
Test support of show_hidden_initial by ModelMultipleChoiceField .
"""
class WriterForm ( forms . Form ) :
persons = forms . ModelMultipleChoiceField ( show_hidden_initial = True ,
queryset = Writer . objects . all ( ) )
person1 = Writer . objects . create ( name = " Person 1 " )
person2 = Writer . objects . create ( name = " Person 2 " )
form = WriterForm ( initial = { ' persons ' : [ person1 , person2 ] } ,
data = { ' initial-persons ' : [ str ( person1 . pk ) , str ( person2 . pk ) ] ,
' persons ' : [ str ( person1 . pk ) , str ( person2 . pk ) ] } )
self . assertTrue ( form . is_valid ( ) )
self . assertFalse ( form . has_changed ( ) )
form = WriterForm ( initial = { ' persons ' : [ person1 , person2 ] } ,
data = { ' initial-persons ' : [ str ( person1 . pk ) , str ( person2 . pk ) ] ,
' persons ' : [ str ( person2 . pk ) ] } )
self . assertTrue ( form . is_valid ( ) )
self . assertTrue ( form . has_changed ( ) )
2014-06-16 07:47:45 +00:00
def test_model_multiple_choice_field_22745 ( self ) :
"""
#22745 -- Make sure that ModelMultipleChoiceField with
CheckboxSelectMultiple widget doesn ' t produce unnecessary db queries
when accessing its BoundField ' s attrs.
"""
class ModelMultipleChoiceForm ( forms . Form ) :
categories = forms . ModelMultipleChoiceField ( Category . objects . all ( ) , widget = forms . CheckboxSelectMultiple )
form = ModelMultipleChoiceForm ( )
field = form [ ' categories ' ] # BoundField
template = Template ( ' {{ field.name }} {{ field }} {{ field.help_text }} ' )
with self . assertNumQueries ( 1 ) :
template . render ( Context ( { ' field ' : field } ) )
2014-12-11 13:31:03 +00:00
def test_show_hidden_initial_changed_queries_efficiently ( self ) :
class WriterForm ( forms . Form ) :
persons = forms . ModelMultipleChoiceField (
show_hidden_initial = True , queryset = Writer . objects . all ( ) )
writers = ( Writer . objects . create ( name = str ( x ) ) for x in range ( 0 , 50 ) )
writer_pks = tuple ( x . pk for x in writers )
form = WriterForm ( data = { ' initial-persons ' : writer_pks } )
with self . assertNumQueries ( 1 ) :
self . assertTrue ( form . has_changed ( ) )
def test_clean_does_deduplicate_values ( self ) :
class WriterForm ( forms . Form ) :
persons = forms . ModelMultipleChoiceField ( queryset = Writer . objects . all ( ) )
person1 = Writer . objects . create ( name = " Person 1 " )
form = WriterForm ( data = { } )
queryset = form . fields [ ' persons ' ] . clean ( [ str ( person1 . pk ) ] * 50 )
sql , params = queryset . query . sql_with_params ( )
self . assertEqual ( len ( params ) , 1 )
2014-03-14 14:18:08 +00:00
class ModelOneToOneFieldTests ( TestCase ) :
2014-03-14 08:44:56 +00:00
def test_modelform_onetoonefield ( self ) :
class ImprovedArticleForm ( forms . ModelForm ) :
class Meta :
model = ImprovedArticle
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
class ImprovedArticleWithParentLinkForm ( forms . ModelForm ) :
class Meta :
model = ImprovedArticleWithParentLink
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
self . assertEqual ( list ( ImprovedArticleForm . base_fields ) , [ ' article ' ] )
2012-08-14 21:38:35 +00:00
self . assertEqual ( list ( ImprovedArticleWithParentLinkForm . base_fields ) , [ ] )
2011-06-10 14:08:51 +00:00
2014-03-14 08:44:56 +00:00
def test_modelform_subclassed_model ( self ) :
class BetterWriterForm ( forms . ModelForm ) :
class Meta :
# BetterWriter model is a subclass of Writer with an additional `score` field
model = BetterWriter
fields = ' __all__ '
bw = BetterWriter . objects . create ( name = ' Joe Better ' , score = 10 )
2012-08-14 21:38:35 +00:00
self . assertEqual ( sorted ( model_to_dict ( bw ) ) ,
2013-06-10 10:22:40 +00:00
[ ' id ' , ' name ' , ' score ' , ' writer_ptr ' ] )
2011-06-10 14:08:51 +00:00
2013-06-10 10:22:40 +00:00
form = BetterWriterForm ( { ' name ' : ' Some Name ' , ' score ' : 12 } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( form . is_valid ( ) )
2011-06-10 14:08:51 +00:00
bw2 = form . save ( )
2014-03-14 08:44:56 +00:00
self . assertEqual ( bw2 . score , 12 )
def test_onetoonefield ( self ) :
class WriterProfileForm ( forms . ModelForm ) :
class Meta :
# WriterProfile has a OneToOneField to Writer
model = WriterProfile
fields = ' __all__ '
self . w_royko = Writer . objects . create ( name = ' Mike Royko ' )
self . w_woodward = Writer . objects . create ( name = ' Bob Woodward ' )
2011-06-10 14:08:51 +00:00
2013-06-10 10:22:40 +00:00
form = WriterProfileForm ( )
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual ( form . as_p ( ) , ''' <p><label for= " id_writer " >Writer:</label> <select name= " writer " id= " id_writer " >
2011-06-10 14:08:51 +00:00
< option value = " " selected = " selected " > - - - - - - - - - < / option >
2011-08-21 18:09:08 +00:00
< option value = " %s " > Bob Woodward < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 14:08:51 +00:00
< / select > < / p >
2014-03-14 08:44:56 +00:00
< p > < label for = " id_age " > Age : < / label > < input type = " number " name = " age " id = " id_age " min = " 0 " / > < / p > ''' % (self.w_woodward.pk, self.w_royko.pk))
2011-06-10 14:08:51 +00:00
data = {
2014-03-14 08:44:56 +00:00
' writer ' : six . text_type ( self . w_woodward . pk ) ,
2012-06-07 16:08:47 +00:00
' age ' : ' 65 ' ,
2011-06-10 14:08:51 +00:00
}
2013-06-10 10:22:40 +00:00
form = WriterProfileForm ( data )
2011-06-10 14:08:51 +00:00
instance = form . save ( )
2012-07-20 12:48:51 +00:00
self . assertEqual ( six . text_type ( instance ) , ' Bob Woodward is 65 ' )
2011-06-10 14:08:51 +00:00
2013-06-10 10:22:40 +00:00
form = WriterProfileForm ( instance = instance )
2012-01-31 20:36:11 +00:00
self . assertHTMLEqual ( form . as_p ( ) , ''' <p><label for= " id_writer " >Writer:</label> <select name= " writer " id= " id_writer " >
2011-06-10 14:08:51 +00:00
< option value = " " > - - - - - - - - - < / option >
2011-08-21 18:09:08 +00:00
< option value = " %s " selected = " selected " > Bob Woodward < / option >
< option value = " %s " > Mike Royko < / option >
2011-06-10 14:08:51 +00:00
< / select > < / p >
2014-03-14 08:44:56 +00:00
< p > < label for = " id_age " > Age : < / label > < input type = " number " name = " age " value = " 65 " id = " id_age " min = " 0 " / > < / p > ''' % (self.w_woodward.pk, self.w_royko.pk))
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
def test_assignment_of_none ( self ) :
class AuthorForm ( forms . ModelForm ) :
class Meta :
model = Author
fields = [ ' publication ' , ' full_name ' ]
publication = Publication . objects . create ( title = " Pravda " ,
date_published = datetime . date ( 1991 , 8 , 22 ) )
author = Author . objects . create ( publication = publication , full_name = ' John Doe ' )
form = AuthorForm ( { ' publication ' : ' ' , ' full_name ' : ' John Doe ' } , instance = author )
self . assertTrue ( form . is_valid ( ) )
self . assertEqual ( form . cleaned_data [ ' publication ' ] , None )
author = form . save ( )
# author object returned from form still retains original publication object
# that's why we need to retrieve it from database again
new_author = Author . objects . get ( pk = author . pk )
self . assertEqual ( new_author . publication , None )
def test_assignment_of_none_null_false ( self ) :
class AuthorForm ( forms . ModelForm ) :
class Meta :
model = Author1
fields = [ ' publication ' , ' full_name ' ]
publication = Publication . objects . create ( title = " Pravda " ,
date_published = datetime . date ( 1991 , 8 , 22 ) )
author = Author1 . objects . create ( publication = publication , full_name = ' John Doe ' )
form = AuthorForm ( { ' publication ' : ' ' , ' full_name ' : ' John Doe ' } , instance = author )
self . assertFalse ( form . is_valid ( ) )
class FileAndImageFieldTests ( TestCase ) :
def test_clean_false ( self ) :
"""
If the ` ` clean ` ` method on a non - required FileField receives False as
the data ( meaning clear the field value ) , it returns False , regardless
of the value of ` ` initial ` ` .
"""
f = forms . FileField ( required = False )
self . assertEqual ( f . clean ( False ) , False )
self . assertEqual ( f . clean ( False , ' initial ' ) , False )
def test_clean_false_required ( self ) :
"""
If the ` ` clean ` ` method on a required FileField receives False as the
data , it has the same effect as None : initial is returned if non - empty ,
otherwise the validation catches the lack of a required value .
"""
f = forms . FileField ( required = True )
self . assertEqual ( f . clean ( False , ' initial ' ) , ' initial ' )
self . assertRaises ( ValidationError , f . clean , False )
def test_full_clear ( self ) :
"""
Integration happy - path test that a model FileField can actually be set
and cleared via a ModelForm .
"""
class DocumentForm ( forms . ModelForm ) :
class Meta :
model = Document
fields = ' __all__ '
form = DocumentForm ( )
2014-10-28 10:02:56 +00:00
self . assertIn ( ' name= " myfile " ' , six . text_type ( form ) )
self . assertNotIn ( ' myfile-clear ' , six . text_type ( form ) )
2014-03-14 14:18:08 +00:00
form = DocumentForm ( files = { ' myfile ' : SimpleUploadedFile ( ' something.txt ' , b ' content ' ) } )
self . assertTrue ( form . is_valid ( ) )
doc = form . save ( commit = False )
self . assertEqual ( doc . myfile . name , ' something.txt ' )
form = DocumentForm ( instance = doc )
2014-10-28 10:02:56 +00:00
self . assertIn ( ' myfile-clear ' , six . text_type ( form ) )
2014-03-14 14:18:08 +00:00
form = DocumentForm ( instance = doc , data = { ' myfile-clear ' : ' true ' } )
doc = form . save ( commit = False )
self . assertEqual ( bool ( doc . myfile ) , False )
def test_clear_and_file_contradiction ( self ) :
"""
If the user submits a new file upload AND checks the clear checkbox ,
they get a validation error , and the bound redisplay of the form still
includes the current file and the clear checkbox .
"""
class DocumentForm ( forms . ModelForm ) :
class Meta :
model = Document
fields = ' __all__ '
form = DocumentForm ( files = { ' myfile ' : SimpleUploadedFile ( ' something.txt ' , b ' content ' ) } )
self . assertTrue ( form . is_valid ( ) )
doc = form . save ( commit = False )
form = DocumentForm ( instance = doc ,
files = { ' myfile ' : SimpleUploadedFile ( ' something.txt ' , b ' content ' ) } ,
data = { ' myfile-clear ' : ' true ' } )
self . assertTrue ( not form . is_valid ( ) )
self . assertEqual ( form . errors [ ' myfile ' ] ,
[ ' Please either submit a file or check the clear checkbox, not both. ' ] )
rendered = six . text_type ( form )
2014-10-28 10:02:56 +00:00
self . assertIn ( ' something.txt ' , rendered )
self . assertIn ( ' myfile-clear ' , rendered )
2014-03-14 14:18:08 +00:00
def test_file_field_data ( self ) :
2011-06-10 14:08:51 +00:00
# Test conditions when files is either not given or empty.
2012-06-07 16:08:47 +00:00
f = TextFileForm ( data = { ' description ' : ' Assistance ' } )
2014-03-14 08:44:56 +00:00
self . assertFalse ( f . is_valid ( ) )
2012-06-07 16:08:47 +00:00
f = TextFileForm ( data = { ' description ' : ' Assistance ' } , files = { } )
2014-03-14 08:44:56 +00:00
self . assertFalse ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
# Upload a file and ensure it all works as expected.
f = TextFileForm (
2013-10-19 23:33:10 +00:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test1.txt ' , b ' hello world ' ) } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
self . assertEqual ( type ( f . cleaned_data [ ' file ' ] ) , SimpleUploadedFile )
instance = f . save ( )
self . assertEqual ( instance . file . name , ' tests/test1.txt ' )
instance . file . delete ( )
2014-03-14 08:44:56 +00:00
# If the previous file has been deleted, the file name can be reused
2011-06-10 14:08:51 +00:00
f = TextFileForm (
2013-10-19 23:33:10 +00:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test1.txt ' , b ' hello world ' ) } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-19 23:33:10 +00:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test-maxlength.txt ' , b ' hello world ' ) } )
2014-03-14 08:44:56 +00:00
self . assertFalse ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
# 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-19 23:33:10 +00:00
data = { ' description ' : ' Assistance ' } ,
instance = instance )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-19 23:33:10 +00:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test2.txt ' , b ' hello world ' ) } , instance = instance )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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 ( )
2014-03-14 14:18:08 +00:00
def test_filefield_required_false ( self ) :
2011-06-10 14:08:51 +00:00
# Test the non-required FileField
2012-06-07 16:08:47 +00:00
f = TextFileForm ( data = { ' description ' : ' Assistance ' } )
2011-06-10 14:08:51 +00:00
f . fields [ ' file ' ] . required = False
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
instance = f . save ( )
self . assertEqual ( instance . file . name , ' ' )
f = TextFileForm (
2013-10-19 23:33:10 +00:00
data = { ' description ' : ' Assistance ' } ,
files = { ' file ' : SimpleUploadedFile ( ' test3.txt ' , b ' hello world ' ) } , instance = instance )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-19 23:33:10 +00:00
data = { ' description ' : ' New Description ' } ,
instance = instance )
2011-06-10 14:08:51 +00:00
f . fields [ ' file ' ] . required = False
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
instance = f . save ( )
2012-06-07 16:08:47 +00:00
self . assertEqual ( instance . description , ' New Description ' )
2011-06-10 14:08:51 +00: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 ( )
2014-03-14 14:18:08 +00:00
def test_custom_file_field_save ( self ) :
"""
Regression for #11149: save_form_data should be called only once
"""
class CFFForm ( forms . ModelForm ) :
class Meta :
model = CustomFF
fields = ' __all__ '
# It's enough that the form saves without error -- the custom save routine will
# generate an AssertionError if it is called more than once during save.
form = CFFForm ( data = { ' f ' : None } )
form . save ( )
2014-07-26 01:23:01 +00:00
def test_file_field_multiple_save ( self ) :
"""
Simulate a file upload and check how many times Model . save ( ) gets
called . Test for bug #639.
"""
class PhotoForm ( forms . ModelForm ) :
class Meta :
model = Photo
fields = ' __all__ '
# Grab an image for testing.
filename = os . path . join ( os . path . dirname ( upath ( __file__ ) ) , " test.png " )
with open ( filename , " rb " ) as fp :
img = fp . read ( )
# Fake a POST QueryDict and FILES MultiValueDict.
data = { ' title ' : ' Testing ' }
files = { " image " : SimpleUploadedFile ( ' test.png ' , img , ' image/png ' ) }
form = PhotoForm ( data = data , files = files )
p = form . save ( )
try :
# Check the savecount stored on the object (see the model).
self . assertEqual ( p . _savecount , 1 )
finally :
# Delete the "uploaded" file to avoid clogging /tmp.
p = Photo . objects . get ( )
p . image . delete ( save = False )
2014-03-14 14:18:08 +00:00
def test_file_path_field_blank ( self ) :
"""
Regression test for #8842: FilePathField(blank=True)
"""
class FPForm ( forms . ModelForm ) :
class Meta :
model = FilePathModel
fields = ' __all__ '
form = FPForm ( )
names = [ p [ 1 ] for p in form [ ' path ' ] . field . choices ]
names . sort ( )
self . assertEqual ( names , [ ' --------- ' , ' __init__.py ' , ' models.py ' , ' tests.py ' ] )
2011-06-10 14:08:51 +00:00
2014-03-21 14:54:53 +00:00
@skipUnless ( test_images , " Pillow not installed " )
2011-06-10 14:08:51 +00:00
def test_image_field ( self ) :
2014-04-26 17:18:45 +00:00
# ImageField and FileField are nearly identical, but they differ slightly when
2011-06-10 14:08:51 +00:00
# it comes to validation. This specifically tests that #6302 is fixed for
# both file fields and image fields.
2012-12-08 10:13:52 +00:00
with open ( os . path . join ( os . path . dirname ( upath ( __file__ ) ) , " test.png " ) , ' rb ' ) as fp :
2012-05-05 12:01:38 +00:00
image_data = fp . read ( )
2012-12-08 10:13:52 +00:00
with open ( os . path . join ( os . path . dirname ( upath ( __file__ ) ) , " test2.png " ) , ' rb ' ) as fp :
2012-05-05 12:01:38 +00:00
image_data2 = fp . read ( )
2011-06-10 14:08:51 +00:00
f = ImageFileForm (
2013-10-19 23:33:10 +00:00
data = { ' description ' : ' An image ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test.png ' , image_data ) } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-19 23:33:10 +00:00
data = { ' description ' : ' An image ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test.png ' , image_data ) } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-07 16:08:47 +00:00
f = ImageFileForm ( data = { ' description ' : ' Look, it changed ' } , instance = instance )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-19 23:33:10 +00:00
data = { ' description ' : ' Changed it ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test2.png ' , image_data2 ) } , instance = instance )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-19 23:33:10 +00:00
data = { ' description ' : ' Changed it ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test2.png ' , image_data2 ) } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-07 16:08:47 +00:00
# Note: In Oracle, we expect a null ImageField to return '' instead of
2011-09-30 21:40:56 +00:00
# None.
if connection . features . interprets_empty_strings_as_nulls :
2012-06-07 16:08:47 +00:00
expected_null_imagefield_repr = ' '
2011-09-30 21:40:56 +00:00
else :
expected_null_imagefield_repr = None
2011-06-10 14:08:51 +00:00
2012-06-07 16:08:47 +00:00
f = OptionalImageFileForm ( data = { ' description ' : ' Test ' } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
instance = f . save ( )
2011-09-30 21:40:56 +00:00
self . assertEqual ( instance . image . name , expected_null_imagefield_repr )
2011-06-10 14:08:51 +00:00
self . assertEqual ( instance . width , None )
self . assertEqual ( instance . height , None )
f = OptionalImageFileForm (
2013-10-19 23:33:10 +00:00
data = { ' description ' : ' And a final one ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test3.png ' , image_data ) } , instance = instance )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-19 23:33:10 +00:00
data = { ' description ' : ' New Description ' } ,
instance = instance )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
instance = f . save ( )
2012-06-07 16:08:47 +00:00
self . assertEqual ( instance . description , ' New Description ' )
2011-06-10 14:08:51 +00: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-19 23:33:10 +00:00
data = { ' description ' : ' And a final one ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test4.png ' , image_data2 ) }
2013-10-18 09:02:43 +00:00
)
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
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-19 23:33:10 +00:00
data = { ' description ' : ' And a final one ' , ' path ' : ' foo ' } ,
files = { ' image ' : SimpleUploadedFile ( ' test4.png ' , image_data ) } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2011-06-10 14:08:51 +00:00
instance = f . save ( )
self . assertEqual ( instance . image . name , ' foo/test4.png ' )
instance . delete ( )
2014-03-20 17:30:41 +00:00
2014-03-14 14:18:08 +00:00
class ModelOtherFieldTests ( TestCase ) :
def test_big_integer_field ( self ) :
bif = BigIntForm ( { ' biggie ' : ' -9223372036854775808 ' } )
self . assertTrue ( bif . is_valid ( ) )
bif = BigIntForm ( { ' biggie ' : ' -9223372036854775809 ' } )
self . assertFalse ( bif . is_valid ( ) )
self . assertEqual ( bif . errors , { ' biggie ' : [ ' Ensure this value is greater than or equal to -9223372036854775808. ' ] } )
bif = BigIntForm ( { ' biggie ' : ' 9223372036854775807 ' } )
self . assertTrue ( bif . is_valid ( ) )
bif = BigIntForm ( { ' biggie ' : ' 9223372036854775808 ' } )
self . assertFalse ( bif . is_valid ( ) )
self . assertEqual ( bif . errors , { ' biggie ' : [ ' Ensure this value is less than or equal to 9223372036854775807. ' ] } )
def test_comma_separated_integer_field ( self ) :
class CommaSeparatedIntegerForm ( forms . ModelForm ) :
class Meta :
model = CommaSeparatedInteger
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,2,3 ' } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2012-06-07 16:08:47 +00:00
self . assertEqual ( f . cleaned_data , { ' field ' : ' 1,2,3 ' } )
2011-06-10 14:08:51 +00:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1a,2 ' } )
2012-06-07 16:08:47 +00:00
self . assertEqual ( f . errors , { ' field ' : [ ' Enter only digits separated by commas. ' ] } )
2011-06-10 14:08:51 +00:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' ,,,, ' } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2012-06-07 16:08:47 +00:00
self . assertEqual ( f . cleaned_data , { ' field ' : ' ,,,, ' } )
2011-06-10 14:08:51 +00:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1.2 ' } )
2012-06-07 16:08:47 +00:00
self . assertEqual ( f . errors , { ' field ' : [ ' Enter only digits separated by commas. ' ] } )
2011-06-10 14:08:51 +00:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,a,2 ' } )
2012-06-07 16:08:47 +00:00
self . assertEqual ( f . errors , { ' field ' : [ ' Enter only digits separated by commas. ' ] } )
2011-06-10 14:08:51 +00:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,,2 ' } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2012-06-07 16:08:47 +00:00
self . assertEqual ( f . cleaned_data , { ' field ' : ' 1,,2 ' } )
2011-06-10 14:08:51 +00:00
f = CommaSeparatedIntegerForm ( { ' field ' : ' 1 ' } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( f . is_valid ( ) )
2012-06-07 16:08:47 +00:00
self . assertEqual ( f . cleaned_data , { ' field ' : ' 1 ' } )
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
def test_url_on_modelform ( self ) :
" Check basic URL field validation on model forms "
class HomepageForm ( forms . ModelForm ) :
class Meta :
model = Homepage
fields = ' __all__ '
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
self . assertFalse ( HomepageForm ( { ' url ' : ' foo ' } ) . is_valid ( ) )
self . assertFalse ( HomepageForm ( { ' url ' : ' http:// ' } ) . is_valid ( ) )
self . assertFalse ( HomepageForm ( { ' url ' : ' http://example ' } ) . is_valid ( ) )
self . assertFalse ( HomepageForm ( { ' url ' : ' http://example. ' } ) . is_valid ( ) )
self . assertFalse ( HomepageForm ( { ' url ' : ' http://com. ' } ) . is_valid ( ) )
self . assertTrue ( HomepageForm ( { ' url ' : ' http://localhost ' } ) . is_valid ( ) )
self . assertTrue ( HomepageForm ( { ' url ' : ' http://example.com ' } ) . is_valid ( ) )
self . assertTrue ( HomepageForm ( { ' url ' : ' http://www.example.com ' } ) . is_valid ( ) )
self . assertTrue ( HomepageForm ( { ' url ' : ' http://www.example.com:8000 ' } ) . is_valid ( ) )
self . assertTrue ( HomepageForm ( { ' url ' : ' http://www.example.com/test ' } ) . is_valid ( ) )
self . assertTrue ( HomepageForm ( { ' url ' : ' http://www.example.com:8000/test ' } ) . is_valid ( ) )
self . assertTrue ( HomepageForm ( { ' url ' : ' http://example.com/foo/bar ' } ) . is_valid ( ) )
def test_http_prefixing ( self ) :
"""
If the http : / / prefix is omitted on form input , the field adds it again . ( Refs #13613)
"""
class HomepageForm ( forms . ModelForm ) :
class Meta :
model = Homepage
fields = ' __all__ '
form = HomepageForm ( { ' url ' : ' example.com ' } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( form . is_valid ( ) )
2014-03-26 18:51:17 +00:00
self . assertEqual ( form . cleaned_data [ ' url ' ] , ' http://example.com ' )
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
form = HomepageForm ( { ' url ' : ' example.com/test ' } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( form . is_valid ( ) )
2014-03-14 14:18:08 +00:00
self . assertEqual ( form . cleaned_data [ ' url ' ] , ' http://example.com/test ' )
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
class OtherModelFormTests ( TestCase ) :
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 ( )
self . assertHTMLEqual ( six . text_type ( f . media ) , ''' <link href= " /some/form/css " type= " text/css " media= " all " rel= " stylesheet " />
< script type = " text/javascript " src = " /some/form/javascript " > < / script > ''' )
2011-06-10 14:08:51 +00:00
2014-03-14 14:18:08 +00:00
def test_choices_type ( self ) :
2011-06-10 14:08:51 +00:00
# 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 12:31:38 +00:00
Inventory . objects . create ( barcode = 22 , name = ' Pear ' )
2011-06-10 14:08:51 +00: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-07 16:08:47 +00:00
( ' ' , ' --------- ' ) ,
( 86 , ' Apple ' ) ,
( 87 , ' Core ' ) ,
( 22 , ' Pear ' ) ) )
2011-06-10 14:08:51 +00:00
form = InventoryForm ( instance = core )
2012-07-20 12:48:51 +00:00
self . assertHTMLEqual ( six . text_type ( form [ ' parent ' ] ) , ''' <select name= " parent " id= " id_parent " >
2011-06-10 14:08:51 +00: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 10:21:07 +00:00
2011-06-10 14:08:51 +00:00
class Meta :
model = Category
fields = [ ' description ' , ' url ' ]
2012-08-14 21:38:35 +00:00
self . assertEqual ( list ( CategoryForm . base_fields ) ,
2011-06-10 14:08:51 +00:00
[ ' description ' , ' url ' ] )
2012-07-20 12:48:51 +00: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 14:08:51 +00: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-07 16:08:47 +00:00
self . assertEqual ( tuple ( field . choices ) , ( ( 86 , ' Apple ' ) , ( 87 , ' Core ' ) , ( 22 , ' Pear ' ) ) )
2012-08-14 21:38:35 +00:00
self . assertQuerysetEqual ( field . clean ( [ 86 ] ) , [ ' Apple ' ] )
2011-06-10 14:08:51 +00:00
form = SelectInventoryForm ( { ' items ' : [ 87 , 22 ] } )
2014-03-14 08:44:56 +00:00
self . assertTrue ( form . is_valid ( ) )
2011-06-10 14:08:51 +00:00
self . assertEqual ( len ( form . cleaned_data ) , 1 )
2012-08-14 21:38:35 +00:00
self . assertQuerysetEqual ( form . cleaned_data [ ' items ' ] , [ ' Core ' , ' Pear ' ] )
2011-06-10 14:08:51 +00:00
def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields ( self ) :
2012-08-14 21:38:35 +00:00
self . assertEqual ( list ( CustomFieldForExclusionForm . base_fields ) ,
[ ' name ' ] )
2012-07-20 12:48:51 +00:00
self . assertHTMLEqual ( six . text_type ( CustomFieldForExclusionForm ( ) ) ,
2011-06-10 14:08:51 +00: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-19 18:12:08 +00:00
2013-10-27 01:27:42 +00:00
def test_iterable_model_m2m ( self ) :
2014-03-14 08:44:56 +00:00
class ColourfulItemForm ( forms . ModelForm ) :
class Meta :
model = ColourfulItem
fields = ' __all__ '
2012-12-19 18:12:08 +00:00
colour = Colour . objects . create ( name = ' Blue ' )
form = ColourfulItemForm ( )
self . maxDiff = 1024
2012-12-29 14:25:24 +00: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-19 18:12:08 +00:00
< p > < label for = " id_colours " > Colours : < / label > < select multiple = " multiple " name = " colours " id = " id_colours " >
2012-12-29 14:25:24 +00:00
< option value = " %(blue_pk)s " > Blue < / option >
2014-03-21 23:07:13 +00:00
< / select > < / p > """
2012-12-29 14:25:24 +00:00
% { ' blue_pk ' : colour . pk } )
2013-05-21 21:32:39 +00:00
2015-03-04 19:19:02 +00:00
def test_callable_field_default ( self ) :
class PublicationDefaultsForm ( forms . ModelForm ) :
class Meta :
model = PublicationDefaults
fields = ' __all__ '
form = PublicationDefaultsForm ( )
self . assertHTMLEqual (
form . as_p ( ) ,
""" <p><label for= " id_title " >Title:</label> <input id= " id_title " maxlength= " 30 " name= " title " type= " text " /></p>
< p > < label for = " id_date_published " > Date published : < / label >
< input id = " id_date_published " name = " date_published " type = " text " value = " 2015-03-04 " / >
< input id = " initial-id_date_published " name = " initial-date_published " type = " hidden " value = " 2015-03-04 " / > < / p >
< p > < label for = " id_mode " > Mode : < / label > < select id = " id_mode " name = " mode " >
< option value = " di " selected = " selected " > direct < / option >
< option value = " de " > delayed < / option > < / select >
< input id = " initial-id_mode " name = " initial-mode " type = " hidden " value = " di " / > < / p >
< p > < label for = " id_category " > Category : < / label > < select id = " id_category " name = " category " >
< option value = " 1 " > Games < / option >
< option value = " 2 " > Comics < / option >
< option value = " 3 " selected = " selected " > Novel < / option > < / select >
< input id = " initial-id_category " name = " initial-category " type = " hidden " value = " 3 " / > """
)
empty_data = {
' title ' : ' ' ,
' date_published ' : ' 2015-03-04 ' ,
' initial-date_published ' : ' 2015-03-04 ' ,
' mode ' : ' di ' ,
' initial-mode ' : ' di ' ,
' category ' : ' 3 ' ,
' initial-category ' : ' 3 ' ,
}
bound_form = PublicationDefaultsForm ( empty_data )
self . assertFalse ( bound_form . has_changed ( ) )
2014-03-14 14:18:08 +00:00
class ModelFormCustomErrorTests ( TestCase ) :
2013-10-27 01:27:42 +00:00
def test_custom_error_messages ( self ) :
2013-06-05 18:55:05 +00: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 01:27:42 +00:00
def test_model_clean_error_messages ( self ) :
2013-08-05 19:26:51 +00:00
data = { ' name1 ' : ' FORBIDDEN_VALUE ' , ' name2 ' : ' ABC ' }
2014-03-14 14:18:08 +00:00
form = CustomErrorMessageForm ( data )
self . assertFalse ( form . is_valid ( ) )
2013-08-05 19:26:51 +00:00
self . assertHTMLEqual (
2014-03-14 14:18:08 +00:00
str ( form . errors [ ' name1 ' ] ) ,
2013-08-05 19:26:51 +00:00
' <ul class= " errorlist " ><li>Model.clean() error messages.</li></ul> '
)
2014-11-18 17:58:43 +00:00
data = { ' name1 ' : ' FORBIDDEN_VALUE2 ' , ' name2 ' : ' ABC ' }
form = CustomErrorMessageForm ( data )
self . assertFalse ( form . is_valid ( ) )
self . assertHTMLEqual (
str ( form . errors [ ' name1 ' ] ) ,
' <ul class= " errorlist " ><li>Model.clean() error messages (simpler syntax).</li></ul> '
)
2014-03-14 14:18:08 +00:00
data = { ' name1 ' : ' GLOBAL_ERROR ' , ' name2 ' : ' ABC ' }
form = CustomErrorMessageForm ( data )
self . assertFalse ( form . is_valid ( ) )
self . assertEqual ( form . errors [ ' __all__ ' ] , [ ' Global error message. ' ] )
class CustomCleanTests ( TestCase ) :
def test_override_clean ( self ) :
"""
Regression for #12596: Calling super from ModelForm.clean() should be
optional .
"""
class TripleFormWithCleanOverride ( forms . ModelForm ) :
class Meta :
model = Triple
fields = ' __all__ '
def clean ( self ) :
if not self . cleaned_data [ ' left ' ] == self . cleaned_data [ ' right ' ] :
raise forms . ValidationError ( ' Left and right should be equal ' )
return self . cleaned_data
form = TripleFormWithCleanOverride ( { ' left ' : 1 , ' middle ' : 2 , ' right ' : 1 } )
self . assertTrue ( form . is_valid ( ) )
# form.instance.left will be None if the instance was not constructed
# by form.full_clean().
self . assertEqual ( form . instance . left , 1 )
def test_model_form_clean_applies_to_model ( self ) :
"""
Regression test for #12960. Make sure the cleaned_data returned from
ModelForm . clean ( ) is applied to the model instance .
"""
class CategoryForm ( forms . ModelForm ) :
class Meta :
model = Category
fields = ' __all__ '
def clean ( self ) :
self . cleaned_data [ ' name ' ] = self . cleaned_data [ ' name ' ] . upper ( )
return self . cleaned_data
data = { ' name ' : ' Test ' , ' slug ' : ' test ' , ' url ' : ' /test ' }
form = CategoryForm ( data )
category = form . save ( )
self . assertEqual ( category . name , ' TEST ' )
2013-08-05 19:26:51 +00:00
2013-05-21 21:32:39 +00:00
2013-07-20 19:25:27 +00: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 15:42:33 +00:00
2014-05-24 09:52:18 +00:00
def test_field_removal ( self ) :
2013-10-14 15:42:33 +00:00
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-01 19:23:31 +00:00
2014-05-24 09:52:18 +00:00
def test_field_removal_name_clashes ( self ) :
""" Regression test for https://code.djangoproject.com/ticket/22510. """
class MyForm ( forms . ModelForm ) :
media = forms . CharField ( )
class Meta :
model = Writer
fields = ' __all__ '
class SubForm ( MyForm ) :
media = None
self . assertIn ( ' media ' , MyForm ( ) . fields )
self . assertNotIn ( ' media ' , SubForm ( ) . fields )
self . assertTrue ( hasattr ( MyForm , ' media ' ) )
self . assertTrue ( hasattr ( SubForm , ' media ' ) )
2014-02-01 19:23:31 +00:00
2014-03-14 14:18:08 +00:00
class StumpJokeForm ( forms . ModelForm ) :
class Meta :
model = StumpJoke
fields = ' __all__ '
2014-11-12 20:18:11 +00:00
class CustomFieldWithQuerysetButNoLimitChoicesTo ( forms . Field ) :
queryset = 42
class StumpJokeWithCustomFieldForm ( forms . ModelForm ) :
custom = CustomFieldWithQuerysetButNoLimitChoicesTo ( )
2014-11-13 09:07:44 +00:00
2014-11-12 20:18:11 +00:00
class Meta :
model = StumpJoke
fields = ( ) # We don't need any fields from the model
2014-02-01 19:23:31 +00: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 )
2014-03-14 14:18:08 +00:00
2014-11-12 20:18:11 +00:00
def test_custom_field_with_queryset_but_no_limit_choices_to ( self ) :
"""
Regression test for #23795: Make sure a custom field with a `queryset`
attribute but no ` limit_choices_to ` still works .
"""
f = StumpJokeWithCustomFieldForm ( )
self . assertEqual ( f . fields [ ' custom ' ] . queryset , 42 )
2014-03-14 14:18:08 +00:00
class FormFieldCallbackTests ( TestCase ) :
def test_baseform_with_widgets_in_meta ( self ) :
""" Regression for #13095: Using base forms with widgets defined in Meta should not raise errors. """
widget = forms . Textarea ( )
class BaseForm ( forms . ModelForm ) :
class Meta :
model = Person
widgets = { ' name ' : widget }
fields = " __all__ "
Form = modelform_factory ( Person , form = BaseForm )
2014-10-28 10:02:56 +00:00
self . assertIs ( Form . base_fields [ ' name ' ] . widget , widget )
2014-03-14 14:18:08 +00:00
def test_factory_with_widget_argument ( self ) :
""" Regression for #15315: modelform_factory should accept widgets
argument
"""
widget = forms . Textarea ( )
# Without a widget should not set the widget to textarea
Form = modelform_factory ( Person , fields = " __all__ " )
self . assertNotEqual ( Form . base_fields [ ' name ' ] . widget . __class__ , forms . Textarea )
# With a widget should not set the widget to textarea
Form = modelform_factory ( Person , fields = " __all__ " , widgets = { ' name ' : widget } )
self . assertEqual ( Form . base_fields [ ' name ' ] . widget . __class__ , forms . Textarea )
def test_modelform_factory_without_fields ( self ) :
""" Regression for #19733 """
2014-03-22 00:44:34 +00:00
message = (
" Calling modelform_factory without defining ' fields ' or ' exclude ' "
" explicitly is prohibited. "
)
with self . assertRaisesMessage ( ImproperlyConfigured , message ) :
2014-03-14 14:18:08 +00:00
modelform_factory ( Person )
def test_modelform_factory_with_all_fields ( self ) :
""" Regression for #19733 """
form = modelform_factory ( Person , fields = " __all__ " )
self . assertEqual ( list ( form . base_fields ) , [ " name " ] )
def test_custom_callback ( self ) :
""" Test that a custom formfield_callback is used if provided """
callback_args = [ ]
def callback ( db_field , * * kwargs ) :
callback_args . append ( ( db_field , kwargs ) )
return db_field . formfield ( * * kwargs )
widget = forms . Textarea ( )
class BaseForm ( forms . ModelForm ) :
class Meta :
model = Person
widgets = { ' name ' : widget }
fields = " __all__ "
modelform_factory ( Person , form = BaseForm , formfield_callback = callback )
id_field , name_field = Person . _meta . fields
self . assertEqual ( callback_args ,
[ ( id_field , { } ) , ( name_field , { ' widget ' : widget } ) ] )
def test_bad_callback ( self ) :
# A bad callback provided by user still gives an error
self . assertRaises ( TypeError , modelform_factory , Person , fields = " __all__ " ,
formfield_callback = ' not a function or callable ' )
class LocalizedModelFormTest ( TestCase ) :
def test_model_form_applies_localize_to_some_fields ( self ) :
class PartiallyLocalizedTripleForm ( forms . ModelForm ) :
class Meta :
model = Triple
localized_fields = ( ' left ' , ' right ' , )
fields = ' __all__ '
f = PartiallyLocalizedTripleForm ( { ' left ' : 10 , ' middle ' : 10 , ' right ' : 10 } )
self . assertTrue ( f . is_valid ( ) )
self . assertTrue ( f . fields [ ' left ' ] . localize )
self . assertFalse ( f . fields [ ' middle ' ] . localize )
self . assertTrue ( f . fields [ ' right ' ] . localize )
def test_model_form_applies_localize_to_all_fields ( self ) :
class FullyLocalizedTripleForm ( forms . ModelForm ) :
class Meta :
model = Triple
localized_fields = ' __all__ '
fields = ' __all__ '
f = FullyLocalizedTripleForm ( { ' left ' : 10 , ' middle ' : 10 , ' right ' : 10 } )
self . assertTrue ( f . is_valid ( ) )
self . assertTrue ( f . fields [ ' left ' ] . localize )
self . assertTrue ( f . fields [ ' middle ' ] . localize )
self . assertTrue ( f . fields [ ' right ' ] . localize )
def test_model_form_refuses_arbitrary_string ( self ) :
with self . assertRaises ( TypeError ) :
class BrokenLocalizedTripleForm ( forms . ModelForm ) :
class Meta :
model = Triple
localized_fields = " foo "
class CustomMetaclass ( ModelFormMetaclass ) :
def __new__ ( cls , name , bases , attrs ) :
new = super ( CustomMetaclass , cls ) . __new__ ( cls , name , bases , attrs )
new . base_fields = { }
return new
class CustomMetaclassForm ( six . with_metaclass ( CustomMetaclass , forms . ModelForm ) ) :
pass
class CustomMetaclassTestCase ( TestCase ) :
def test_modelform_factory_metaclass ( self ) :
new_cls = modelform_factory ( Person , fields = " __all__ " , form = CustomMetaclassForm )
self . assertEqual ( new_cls . base_fields , { } )