2006-12-15 13:46:11 +08:00
"""
2007-12-03 03:29:54 +08:00
XX . Generating HTML forms from models
2008-08-12 22:15:38 +08:00
This is mostly just a reworking of the ` ` form_for_model ` ` / ` ` form_for_instance ` `
tests to use ` ` ModelForm ` ` . As such , the text may not make sense in all cases ,
and the examples are probably a poor fit for the ` ` ModelForm ` ` syntax . In other
words , most of these tests should be rewritten .
2006-12-15 13:46:11 +08:00
"""
2008-01-18 02:03:21 +08:00
import os
import tempfile
2006-12-15 13:46:11 +08:00
from django . db import models
2008-08-09 04:59:02 +08:00
from django . core . files . storage import FileSystemStorage
2008-10-11 06:13:16 +08:00
temp_storage_dir = tempfile . mkdtemp ( )
temp_storage = FileSystemStorage ( temp_storage_dir )
2006-12-15 13:46:11 +08:00
2007-04-28 22:18:03 +08:00
ARTICLE_STATUS = (
( 1 , ' Draft ' ) ,
( 2 , ' Pending ' ) ,
( 3 , ' Live ' ) ,
)
2008-09-01 04:11:11 +08:00
ARTICLE_STATUS_CHAR = (
( ' d ' , ' Draft ' ) ,
( ' p ' , ' Pending ' ) ,
( ' l ' , ' Live ' ) ,
)
2006-12-15 13:46:11 +08:00
class Category ( models . Model ) :
2007-08-05 13:14:46 +08:00
name = models . CharField ( max_length = 20 )
2007-09-08 13:09:39 +08:00
slug = models . SlugField ( max_length = 20 )
2007-08-05 13:14:46 +08:00
url = models . CharField ( ' The URL ' , max_length = 40 )
2006-12-15 13:46:11 +08:00
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
def __unicode__ ( self ) :
2006-12-15 13:46:11 +08:00
return self . name
2006-12-27 13:23:21 +08:00
class Writer ( models . Model ) :
2007-08-05 13:14:46 +08:00
name = models . CharField ( max_length = 50 , help_text = ' Use both first and last names. ' )
2006-12-27 13:23:21 +08:00
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
def __unicode__ ( self ) :
2006-12-27 13:23:21 +08:00
return self . name
2006-12-15 13:46:11 +08:00
class Article ( models . Model ) :
2007-08-05 13:14:46 +08:00
headline = models . CharField ( max_length = 50 )
2007-09-08 13:09:39 +08:00
slug = models . SlugField ( )
2006-12-30 08:12:02 +08:00
pub_date = models . DateField ( )
2007-02-20 10:59:16 +08:00
created = models . DateField ( editable = False )
2006-12-27 13:23:21 +08:00
writer = models . ForeignKey ( Writer )
2007-01-11 07:34:37 +08:00
article = models . TextField ( )
2006-12-28 10:34:53 +08:00
categories = models . ManyToManyField ( Category , blank = True )
2008-09-02 03:20:03 +08:00
status = models . PositiveIntegerField ( choices = ARTICLE_STATUS , blank = True , null = True )
2006-12-15 13:46:11 +08:00
2007-02-20 10:59:16 +08:00
def save ( self ) :
import datetime
if not self . id :
self . created = datetime . date . today ( )
return super ( Article , self ) . save ( )
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
def __unicode__ ( self ) :
2006-12-15 13:46:11 +08:00
return self . headline
2008-08-23 03:27:26 +08:00
class ImprovedArticle ( models . Model ) :
article = models . OneToOneField ( Article )
class ImprovedArticleWithParentLink ( models . Model ) :
article = models . OneToOneField ( Article , parent_link = True )
2008-08-25 11:51:25 +08:00
class BetterWriter ( Writer ) :
2010-01-05 11:56:19 +08:00
score = models . IntegerField ( )
2008-08-25 11:51:25 +08:00
2008-08-31 17:49:55 +08:00
class WriterProfile ( models . Model ) :
writer = models . OneToOneField ( Writer , primary_key = True )
age = models . PositiveIntegerField ( )
2008-09-02 06:43:38 +08:00
2008-08-31 17:49:55 +08:00
def __unicode__ ( self ) :
return " %s is %s " % ( self . writer , self . age )
2008-09-02 06:15:35 +08:00
from django . contrib . localflavor . us . models import PhoneNumberField
2007-02-21 13:59:46 +08:00
class PhoneNumber ( models . Model ) :
2008-09-02 06:15:35 +08:00
phone = PhoneNumberField ( )
2007-08-05 13:14:46 +08:00
description = models . CharField ( max_length = 20 )
2007-02-21 13:59:46 +08:00
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
def __unicode__ ( self ) :
2007-02-21 13:59:46 +08:00
return self . phone
2008-01-18 02:03:21 +08:00
class TextFile ( models . Model ) :
description = models . CharField ( max_length = 20 )
2009-03-31 06:52:16 +08:00
file = models . FileField ( storage = temp_storage , upload_to = ' tests ' , max_length = 15 )
2008-01-18 02:03:21 +08:00
def __unicode__ ( self ) :
return self . description
2008-02-14 20:56:49 +08:00
2009-02-17 02:34:28 +08:00
try :
2010-02-15 02:28:28 +08:00
# If PIL is available, try testing ImageFields. Checking for the existence
# of Image is enough for CPython, but for PyPy, you need to check for the
# underlying modules If PIL is not available, ImageField tests are omitted.
# Try to import PIL in either of the two ways it can end up installed.
try :
from PIL import Image , _imaging
except ImportError :
import Image , _imaging
2009-02-17 02:34:28 +08:00
test_images = True
2009-03-15 13:05:26 +08:00
2009-02-17 02:34:28 +08:00
class ImageFile ( models . Model ) :
def custom_upload_path ( self , filename ) :
path = self . path or ' tests '
return ' %s / %s ' % ( path , filename )
2009-03-15 13:05:26 +08:00
2009-02-17 02:34:28 +08:00
description = models . CharField ( max_length = 20 )
2009-05-11 17:57:19 +08:00
# Deliberately put the image field *after* the width/height fields to
# trigger the bug in #10404 with width/height not getting assigned.
2009-02-17 02:34:28 +08:00
width = models . IntegerField ( editable = False )
height = models . IntegerField ( editable = False )
2009-05-11 17:57:19 +08:00
image = models . ImageField ( storage = temp_storage , upload_to = custom_upload_path ,
width_field = ' width ' , height_field = ' height ' )
2009-02-17 02:34:28 +08:00
path = models . CharField ( max_length = 16 , blank = True , default = ' ' )
def __unicode__ ( self ) :
return self . description
2009-03-15 13:05:26 +08:00
2009-02-17 02:34:28 +08:00
class OptionalImageFile ( models . Model ) :
def custom_upload_path ( self , filename ) :
path = self . path or ' tests '
return ' %s / %s ' % ( path , filename )
2009-03-15 13:05:26 +08:00
2009-02-17 02:34:28 +08:00
description = models . CharField ( max_length = 20 )
image = models . ImageField ( storage = temp_storage , upload_to = custom_upload_path ,
2009-03-15 13:05:26 +08:00
width_field = ' width ' , height_field = ' height ' ,
2009-02-17 02:34:28 +08:00
blank = True , null = True )
width = models . IntegerField ( editable = False , null = True )
height = models . IntegerField ( editable = False , null = True )
path = models . CharField ( max_length = 16 , blank = True , default = ' ' )
def __unicode__ ( self ) :
return self . description
except ImportError :
test_images = False
2009-03-15 13:05:26 +08:00
2008-08-29 04:58:10 +08:00
class CommaSeparatedInteger ( models . Model ) :
field = models . CommaSeparatedIntegerField ( max_length = 20 )
def __unicode__ ( self ) :
return self . field
2008-09-02 03:08:08 +08:00
class Product ( models . Model ) :
slug = models . SlugField ( unique = True )
def __unicode__ ( self ) :
return self . slug
class Price ( models . Model ) :
price = models . DecimalField ( max_digits = 10 , decimal_places = 2 )
quantity = models . PositiveIntegerField ( )
def __unicode__ ( self ) :
return u " %s for %s " % ( self . quantity , self . price )
class Meta :
unique_together = ( ( ' price ' , ' quantity ' ) , )
2008-09-01 04:11:11 +08:00
class ArticleStatus ( models . Model ) :
status = models . CharField ( max_length = 2 , choices = ARTICLE_STATUS_CHAR , blank = True , null = True )
2008-09-02 06:43:38 +08:00
class Inventory ( models . Model ) :
barcode = models . PositiveIntegerField ( unique = True )
parent = models . ForeignKey ( ' self ' , to_field = ' barcode ' , blank = True , null = True )
name = models . CharField ( blank = False , max_length = 20 )
2008-09-02 03:08:08 +08:00
2008-09-02 06:43:38 +08:00
def __unicode__ ( self ) :
return self . name
2008-10-21 22:04:24 +08:00
class Book ( models . Model ) :
title = models . CharField ( max_length = 40 )
author = models . ForeignKey ( Writer , blank = True , null = True )
special_id = models . IntegerField ( blank = True , null = True , unique = True )
2009-03-15 13:05:26 +08:00
2008-10-21 22:04:24 +08:00
class Meta :
unique_together = ( ' title ' , ' author ' )
2009-03-15 13:05:26 +08:00
2008-11-06 03:47:44 +08:00
class ExplicitPK ( models . Model ) :
key = models . CharField ( max_length = 20 , primary_key = True )
desc = models . CharField ( max_length = 20 , blank = True , unique = True )
class Meta :
unique_together = ( ' key ' , ' desc ' )
2009-03-15 13:05:26 +08:00
2008-11-06 03:47:44 +08:00
def __unicode__ ( self ) :
return self . key
2008-10-21 22:04:24 +08:00
2009-04-30 21:47:39 +08:00
class Post ( models . Model ) :
title = models . CharField ( max_length = 50 , unique_for_date = ' posted ' , blank = True )
slug = models . CharField ( max_length = 50 , unique_for_year = ' posted ' , blank = True )
subtitle = models . CharField ( max_length = 50 , unique_for_month = ' posted ' , blank = True )
posted = models . DateField ( )
def __unicode__ ( self ) :
return self . name
2009-12-17 23:10:38 +08:00
class BigInt ( models . Model ) :
biggie = models . BigIntegerField ( )
def __unicode__ ( self ) :
return unicode ( self . biggie )
2006-12-15 13:46:11 +08:00
__test__ = { ' API_TESTS ' : """
2008-07-19 09:22:26 +08:00
>> > from django import forms
2008-08-25 11:51:25 +08:00
>> > from django . forms . models import ModelForm , model_to_dict
2008-07-01 23:10:51 +08:00
>> > from django . core . files . uploadedfile import SimpleUploadedFile
2007-12-03 03:29:54 +08:00
The bare bones , absolutely nothing custom , basic case .
>> > class CategoryForm ( ModelForm ) :
. . . class Meta :
. . . model = Category
>> > CategoryForm . base_fields . keys ( )
[ ' name ' , ' slug ' , ' url ' ]
Extra fields .
>> > class CategoryForm ( ModelForm ) :
. . . some_extra_field = forms . BooleanField ( )
. . .
. . . class Meta :
. . . model = Category
>> > CategoryForm . base_fields . keys ( )
[ ' name ' , ' slug ' , ' url ' , ' some_extra_field ' ]
2009-01-20 03:37:31 +08:00
Extra field that has a name collision with a related object accessor .
>> > class WriterForm ( ModelForm ) :
. . . book = forms . CharField ( required = False )
. . .
. . . class Meta :
. . . model = Writer
>> > wf = WriterForm ( { ' name ' : ' Richard Lockridge ' } )
>> > wf . is_valid ( )
True
2007-12-03 03:29:54 +08:00
Replacing a field .
>> > class CategoryForm ( ModelForm ) :
. . . url = forms . BooleanField ( )
. . .
. . . class Meta :
. . . model = Category
>> > CategoryForm . base_fields [ ' url ' ] . __class__
2008-07-19 09:22:26 +08:00
< class ' django . forms . fields . BooleanField ' >
2007-12-03 03:29:54 +08:00
Using ' fields ' .
>> > class CategoryForm ( ModelForm ) :
. . .
. . . class Meta :
. . . model = Category
. . . fields = [ ' url ' ]
>> > CategoryForm . base_fields . keys ( )
[ ' url ' ]
Using ' exclude '
>> > class CategoryForm ( ModelForm ) :
. . .
. . . class Meta :
. . . model = Category
. . . exclude = [ ' url ' ]
>> > CategoryForm . base_fields . keys ( )
[ ' name ' , ' slug ' ]
Using ' fields ' * and * ' exclude ' . Not sure why you ' d want to do this, but uh,
" be liberal in what you accept " and all .
>> > class CategoryForm ( ModelForm ) :
. . .
. . . class Meta :
. . . model = Category
. . . fields = [ ' name ' , ' url ' ]
. . . exclude = [ ' url ' ]
>> > CategoryForm . base_fields . keys ( )
[ ' name ' ]
2010-01-11 03:23:42 +08:00
Using ' widgets '
>> > class CategoryForm ( ModelForm ) :
. . .
. . . class Meta :
. . . model = Category
. . . fields = [ ' name ' , ' url ' , ' slug ' ]
. . . widgets = {
. . . ' name ' : forms . Textarea ,
. . . ' url ' : forms . TextInput ( attrs = { ' class ' : ' url ' } )
. . . }
>> > str ( CategoryForm ( ) [ ' name ' ] )
' <textarea id= " id_name " rows= " 10 " cols= " 40 " name= " name " ></textarea> '
>> > str ( CategoryForm ( ) [ ' url ' ] )
' <input id= " id_url " type= " text " class= " url " name= " url " maxlength= " 40 " /> '
>> > str ( CategoryForm ( ) [ ' slug ' ] )
' <input id= " id_slug " type= " text " name= " slug " maxlength= " 20 " /> '
2007-12-03 03:29:54 +08:00
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 CategoryForm ( ModelForm ) :
. . . class Meta :
. . . model = Category
2008-02-15 01:38:05 +08:00
>> > class OddForm ( CategoryForm ) :
2007-12-03 03:29:54 +08:00
. . . class Meta :
. . . model = Article
2008-02-15 01:38:05 +08:00
OddForm is now an Article - related thing , because BadForm . Meta overrides
CategoryForm . Meta .
>> > OddForm . base_fields . keys ( )
[ ' headline ' , ' slug ' , ' pub_date ' , ' writer ' , ' article ' , ' status ' , ' categories ' ]
2007-12-03 03:29:54 +08:00
>> > class ArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
2008-02-15 01:38:05 +08:00
First class with a Meta class wins .
2007-12-03 03:29:54 +08:00
>> > class BadForm ( ArticleForm , CategoryForm ) :
. . . pass
2008-02-15 01:38:05 +08:00
>> > OddForm . base_fields . keys ( )
[ ' headline ' , ' slug ' , ' pub_date ' , ' writer ' , ' article ' , ' status ' , ' categories ' ]
2007-12-03 03:29:54 +08:00
2008-02-15 01:38:05 +08:00
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 ) .
2007-12-13 11:14:31 +08:00
2008-02-15 01:38:05 +08:00
>> > class CategoryForm ( ModelForm ) :
2007-12-13 11:14:31 +08:00
. . . class Meta :
. . . model = Category
2008-02-15 01:38:05 +08:00
>> > class SubCategoryForm ( CategoryForm ) :
. . . pass
>> > SubCategoryForm . base_fields . keys ( )
[ ' name ' , ' slug ' , ' url ' ]
2007-12-13 11:14:31 +08:00
2008-02-15 01:38:05 +08:00
We can also subclass the Meta inner class to change the fields list .
2008-02-14 20:56:49 +08:00
>> > class CategoryForm ( ModelForm ) :
2008-02-15 01:38:05 +08:00
. . . checkbox = forms . BooleanField ( )
. . .
2008-02-14 20:56:49 +08:00
. . . class Meta :
. . . model = Category
>> > class SubCategoryForm ( CategoryForm ) :
2008-02-15 01:38:05 +08:00
. . . class Meta ( CategoryForm . Meta ) :
. . . exclude = [ ' url ' ]
2008-02-14 20:56:49 +08:00
>> > print SubCategoryForm ( )
< 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 >
2008-02-15 01:38:05 +08:00
< tr > < th > < label for = " id_checkbox " > Checkbox : < / label > < / th > < td > < input type = " checkbox " name = " checkbox " id = " id_checkbox " / > < / td > < / tr >
2008-02-14 20:56:49 +08:00
2009-03-15 13:05:26 +08:00
# test using fields to provide ordering to the fields
>> > class CategoryForm ( ModelForm ) :
. . . class Meta :
. . . model = Category
. . . fields = [ ' url ' , ' name ' ]
>> > CategoryForm . base_fields . keys ( )
[ ' url ' , ' name ' ]
>> > print CategoryForm ( )
< 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 >
>> > class CategoryForm ( ModelForm ) :
. . . class Meta :
. . . model = Category
. . . fields = [ ' slug ' , ' url ' , ' name ' ]
. . . exclude = [ ' url ' ]
>> > CategoryForm . base_fields . keys ( )
[ ' slug ' , ' name ' ]
2007-12-03 03:29:54 +08:00
# Old form_for_x tests #######################################################
2008-07-19 09:22:26 +08:00
>> > from django . forms import ModelForm , CharField
2006-12-28 10:34:53 +08:00
>> > import datetime
2006-12-16 06:33:24 +08:00
>> > Category . objects . all ( )
[ ]
2007-12-03 03:29:54 +08:00
>> > class CategoryForm ( ModelForm ) :
. . . class Meta :
. . . model = Category
2007-12-13 10:48:04 +08:00
>> > f = CategoryForm ( )
2006-12-15 13:46:11 +08:00
>> > print f
2006-12-16 02:32:42 +08:00
< tr > < th > < label for = " id_name " > Name : < / label > < / th > < td > < input id = " id_name " type = " text " name = " name " maxlength = " 20 " / > < / td > < / tr >
2007-09-08 13:09:39 +08:00
< tr > < th > < label for = " id_slug " > Slug : < / label > < / th > < td > < input id = " id_slug " type = " text " name = " slug " maxlength = " 20 " / > < / td > < / tr >
2006-12-16 02:32:42 +08:00
< tr > < th > < label for = " id_url " > The URL : < / label > < / th > < td > < input id = " id_url " type = " text " name = " url " maxlength = " 40 " / > < / td > < / tr >
2006-12-15 13:46:11 +08:00
>> > print f . as_ul ( )
2006-12-16 02:32:42 +08:00
< li > < label for = " id_name " > Name : < / label > < input id = " id_name " type = " text " name = " name " maxlength = " 20 " / > < / li >
2007-09-08 13:09:39 +08:00
< li > < label for = " id_slug " > Slug : < / label > < input id = " id_slug " type = " text " name = " slug " maxlength = " 20 " / > < / li >
2006-12-16 02:32:42 +08:00
< li > < label for = " id_url " > The URL : < / label > < input id = " id_url " type = " text " name = " url " maxlength = " 40 " / > < / li >
2006-12-15 13:46:11 +08:00
>> > print f [ ' name ' ]
2006-12-16 02:32:42 +08:00
< input id = " id_name " type = " text " name = " name " maxlength = " 20 " / >
2006-12-15 13:46:11 +08:00
2007-12-13 10:48:04 +08:00
>> > f = CategoryForm ( auto_id = False )
2006-12-15 13:46:11 +08:00
>> > print f . as_ul ( )
2006-12-16 02:32:42 +08:00
< li > Name : < input type = " text " name = " name " maxlength = " 20 " / > < / li >
2007-09-08 13:09:39 +08:00
< li > Slug : < input type = " text " name = " slug " maxlength = " 20 " / > < / li >
2006-12-16 02:32:42 +08:00
< li > The URL : < input type = " text " name = " url " maxlength = " 40 " / > < / li >
2006-12-16 05:22:13 +08:00
2007-12-13 10:48:04 +08:00
>> > f = CategoryForm ( { ' name ' : ' Entertainment ' , ' slug ' : ' entertainment ' , ' url ' : ' entertainment ' } )
2007-01-09 02:06:22 +08:00
>> > f . is_valid ( )
True
2008-03-20 03:11:51 +08:00
>> > f . cleaned_data [ ' url ' ]
u ' entertainment '
>> > f . cleaned_data [ ' name ' ]
u ' Entertainment '
>> > f . cleaned_data [ ' slug ' ]
u ' entertainment '
2007-01-09 13:22:48 +08:00
>> > obj = f . save ( )
2006-12-16 06:33:24 +08:00
>> > obj
< Category : Entertainment >
>> > Category . objects . all ( )
[ < Category : Entertainment > ]
2007-12-13 10:48:04 +08:00
>> > f = CategoryForm ( { ' name ' : " It ' s a test " , ' slug ' : ' its-test ' , ' url ' : ' test ' } )
2007-01-09 02:06:22 +08:00
>> > f . is_valid ( )
True
2008-03-20 03:11:51 +08:00
>> > f . cleaned_data [ ' url ' ]
u ' test '
>> > f . cleaned_data [ ' name ' ]
u " It ' s a test "
>> > f . cleaned_data [ ' slug ' ]
u ' its-test '
2007-01-09 13:22:48 +08:00
>> > obj = f . save ( )
2006-12-16 06:33:24 +08:00
>> > obj
< Category : It ' s a test>
2007-09-15 08:19:22 +08:00
>> > Category . objects . order_by ( ' name ' )
2006-12-16 06:33:24 +08:00
[ < Category : Entertainment > , < Category : It ' s a test>]
2007-01-09 13:22:48 +08: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 .
2007-12-13 10:48:04 +08:00
>> > f = CategoryForm ( { ' name ' : ' Third test ' , ' slug ' : ' third-test ' , ' url ' : ' third ' } )
2007-01-09 02:06:22 +08:00
>> > f . is_valid ( )
True
2008-03-20 03:11:51 +08:00
>> > f . cleaned_data [ ' url ' ]
u ' third '
>> > f . cleaned_data [ ' name ' ]
u ' Third test '
>> > f . cleaned_data [ ' slug ' ]
u ' third-test '
2007-01-09 13:22:48 +08:00
>> > obj = f . save ( commit = False )
2006-12-16 06:33:24 +08:00
>> > obj
< Category : Third test >
2007-09-15 08:19:22 +08:00
>> > Category . objects . order_by ( ' name ' )
2006-12-16 06:33:24 +08:00
[ < Category : Entertainment > , < Category : It ' s a test>]
>> > obj . save ( )
2007-09-15 08:19:22 +08:00
>> > Category . objects . order_by ( ' name ' )
2006-12-16 06:33:24 +08:00
[ < Category : Entertainment > , < Category : It ' s a test>, <Category: Third test>]
2007-01-09 13:22:48 +08:00
If you call save ( ) with invalid data , you ' ll get a ValueError.
2008-08-23 12:59:25 +08:00
>> > f = CategoryForm ( { ' name ' : ' ' , ' slug ' : ' not a slug! ' , ' url ' : ' foo ' } )
2008-03-20 03:11:51 +08:00
>> > f . errors [ ' name ' ]
[ u ' This field is required. ' ]
>> > f . errors [ ' slug ' ]
2008-08-23 12:59:25 +08:00
[ u " Enter a valid ' slug ' consisting of letters, numbers, underscores or hyphens. " ]
2007-05-15 00:24:51 +08:00
>> > f . cleaned_data
2007-01-09 02:06:22 +08:00
Traceback ( most recent call last ) :
. . .
2007-05-15 00:24:51 +08:00
AttributeError : ' CategoryForm ' object has no attribute ' cleaned_data '
2007-01-09 13:22:48 +08:00
>> > f . save ( )
2006-12-16 06:33:24 +08:00
Traceback ( most recent call last ) :
. . .
ValueError : The Category could not be created because the data didn ' t validate.
2007-12-13 10:48:04 +08:00
>> > f = CategoryForm ( { ' name ' : ' ' , ' slug ' : ' ' , ' url ' : ' foo ' } )
2007-01-09 13:22:48 +08:00
>> > f . save ( )
2006-12-16 06:33:24 +08:00
Traceback ( most recent call last ) :
. . .
ValueError : The Category could not be created because the data didn ' t validate.
2006-12-27 13:23:21 +08:00
Create a couple of Writers .
>> > w = Writer ( name = ' Mike Royko ' )
>> > w . save ( )
>> > w = Writer ( name = ' Bob Woodward ' )
>> > w . save ( )
2007-04-28 22:18:03 +08:00
ManyToManyFields are represented by a MultipleChoiceField , ForeignKeys and any
fields with the ' choices ' attribute are represented by a ChoiceField .
2007-12-03 03:29:54 +08:00
>> > class ArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
2007-12-13 10:48:04 +08:00
>> > f = ArticleForm ( auto_id = False )
2006-12-27 13:15:22 +08:00
>> > print f
< tr > < th > Headline : < / th > < td > < input type = " text " name = " headline " maxlength = " 50 " / > < / td > < / tr >
2007-09-08 13:09:39 +08:00
< tr > < th > Slug : < / th > < td > < input type = " text " name = " slug " maxlength = " 50 " / > < / td > < / tr >
2006-12-27 13:15:22 +08:00
< tr > < th > Pub date : < / th > < td > < input type = " text " name = " pub_date " / > < / td > < / tr >
2006-12-27 13:23:21 +08:00
< tr > < th > Writer : < / th > < td > < select name = " writer " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Mike Royko < / option >
< option value = " 2 " > Bob Woodward < / option >
< / select > < / td > < / tr >
2007-04-09 09:22:45 +08:00
< tr > < th > Article : < / th > < td > < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / td > < / tr >
2007-04-28 22:18:03 +08: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 >
< / select > < / td > < / tr >
2006-12-27 13:15:22 +08:00
< tr > < th > Categories : < / th > < td > < select multiple = " multiple " name = " categories " >
< option value = " 1 " > Entertainment < / option >
< option value = " 2 " > It & #39;s a test</option>
< option value = " 3 " > Third test < / option >
2007-01-29 06:36:02 +08:00
< / select > < br / > Hold down " Control " , or " Command " on a Mac , to select more than one . < / td > < / tr >
2006-12-27 13:15:22 +08:00
2007-05-12 22:42:46 +08:00
You can restrict a form to a subset of the complete list of fields
by providing a ' fields ' argument . If you try to save a
model created with such a form , you need to ensure that the fields
that are _not_ on the form have default values , or are allowed to have
a value of None . If a field isn ' t specified on a form, the object created
from the form can ' t provide a value for that field!
2007-12-03 03:29:54 +08:00
>> > class PartialArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
. . . fields = ( ' headline ' , ' pub_date ' )
2007-12-13 10:48:04 +08:00
>> > f = PartialArticleForm ( auto_id = False )
2007-05-12 22:42:46 +08:00
>> > print f
< tr > < th > Headline : < / th > < td > < input type = " text " name = " headline " maxlength = " 50 " / > < / td > < / tr >
< tr > < th > Pub date : < / th > < td > < input type = " text " name = " pub_date " / > < / td > < / tr >
Fixed #7830 -- Removed all of the remaining, deprecated, non-oldforms features:
* Support for representing files as strings was removed. Use `django.core.files.base.ContentFile` instead.
* Support for representing uploaded files as dictionaries was removed. Use `django.core.files.uploadedfile.SimpleUploadedFile` instead.
* The `filename`, `file_name`, `file_size`, and `chuck` properties of `UploadedFile` were removed. Use the `name`, `name`, `size`, and `chunks` properties instead, respectively.
* The `get_FIELD_filename`, `get_FIELD_url`, `get_FIELD_size`, and `save_FIELD_file` methods for Models with `FileField` fields were removed. Instead, use the `path`, `url`, and `size` attributes and `save` method on the field itself, respectively.
* The `get_FIELD_width` and `get_FIELD_height` methods for Models with `ImageField` fields were removed. Use the `width` and `height` attributes on the field itself instead.
* The dispatcher `connect`, `disconnect`, `send`, and `sendExact` functions were removed. Use the signal object's own `connect`, `disconnect`, `send`, and `send` methods instead, respectively.
* The `form_for_model` and `form_for_instance` functions were removed. Use a `ModelForm` subclass instead.
* Support for importing `django.newforms` was removed. Use `django.forms` instead.
* Support for importing `django.utils.images` was removed. Use `django.core.files.images` instead.
* Support for the `follow` argument in the `create_object` and `update_object` generic views was removed. Use the `django.forms` package and the new `form_class` argument instead.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8291 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-11 05:10:47 +08:00
When the ModelForm is passed an instance , that instance ' s current values are
inserted as ' initial ' data in each Field .
2006-12-28 09:16:29 +08:00
>> > w = Writer . objects . get ( name = ' Mike Royko ' )
2007-12-03 03:29:54 +08:00
>> > class RoykoForm ( ModelForm ) :
. . . class Meta :
. . . model = Writer
2007-12-13 10:48:04 +08:00
>> > f = RoykoForm ( auto_id = False , instance = w )
2006-12-28 09:16:29 +08:00
>> > print f
2007-01-29 06:36:02 +08:00
< tr > < th > Name : < / th > < td > < input type = " text " name = " name " value = " Mike Royko " maxlength = " 50 " / > < br / > Use both first and last names . < / td > < / tr >
2006-12-28 10:34:53 +08:00
2007-09-08 13:09:39 +08:00
>> > art = Article ( headline = ' Test article ' , slug = ' test-article ' , pub_date = datetime . date ( 1988 , 1 , 4 ) , writer = w , article = ' Hello. ' )
2006-12-28 10:34:53 +08:00
>> > art . save ( )
>> > art . id
1
2007-12-03 03:29:54 +08:00
>> > class TestArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
2007-12-13 10:48:04 +08:00
>> > f = TestArticleForm ( auto_id = False , instance = art )
2006-12-28 10:34:53 +08:00
>> > print f . as_ul ( )
< li > Headline : < input type = " text " name = " headline " value = " Test article " maxlength = " 50 " / > < / li >
2007-09-08 13:09:39 +08:00
< li > Slug : < input type = " text " name = " slug " value = " test-article " maxlength = " 50 " / > < / li >
2006-12-28 10:34:53 +08:00
< li > Pub date : < input type = " text " name = " pub_date " value = " 1988-01-04 " / > < / li >
< li > Writer : < select name = " writer " >
< option value = " " > - - - - - - - - - < / option >
< option value = " 1 " selected = " selected " > Mike Royko < / option >
< option value = " 2 " > Bob Woodward < / option >
< / select > < / li >
2007-04-09 09:22:45 +08:00
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > Hello . < / textarea > < / li >
2007-04-28 22:18:03 +08: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 >
2006-12-28 10:34:53 +08:00
< li > Categories : < select multiple = " multiple " name = " categories " >
< option value = " 1 " > Entertainment < / option >
< option value = " 2 " > It & #39;s a test</option>
< option value = " 3 " > Third test < / option >
2007-01-29 06:36:02 +08:00
< / select > Hold down " Control " , or " Command " on a Mac , to select more than one . < / li >
2007-12-13 10:48:04 +08:00
>> > f = TestArticleForm ( { ' headline ' : u ' Test headline ' , ' slug ' : ' test-headline ' , ' pub_date ' : u ' 1984-02-06 ' , ' writer ' : u ' 1 ' , ' article ' : ' Hello. ' } , instance = art )
2010-01-05 11:56:19 +08:00
>> > f . errors
{ }
2007-05-12 22:42:46 +08:00
>> > f . is_valid ( )
True
>> > test_art = f . save ( )
>> > test_art . id
1
>> > test_art = Article . objects . get ( id = 1 )
>> > test_art . headline
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
u ' Test headline '
2007-05-12 22:42:46 +08:00
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
You can create a form over a subset of the available fields
by specifying a ' fields ' argument to form_for_instance .
2007-12-03 03:29:54 +08:00
>> > class PartialArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
. . . fields = ( ' headline ' , ' slug ' , ' pub_date ' )
2007-12-13 10:48:04 +08:00
>> > f = PartialArticleForm ( { ' headline ' : u ' New headline ' , ' slug ' : ' new-headline ' , ' pub_date ' : u ' 1988-01-04 ' } , auto_id = False , instance = art )
2007-05-12 22:42:46 +08:00
>> > print f . as_ul ( )
< li > Headline : < input type = " text " name = " headline " value = " New headline " maxlength = " 50 " / > < / li >
2007-09-08 13:09:39 +08:00
< li > Slug : < input type = " text " name = " slug " value = " new-headline " maxlength = " 50 " / > < / li >
2007-05-12 22:42:46 +08:00
< li > Pub date : < input type = " text " name = " pub_date " value = " 1988-01-04 " / > < / li >
2006-12-28 10:34:53 +08:00
>> > f . is_valid ( )
True
2007-01-09 13:22:48 +08:00
>> > new_art = f . save ( )
2006-12-28 10:34:53 +08:00
>> > new_art . id
1
>> > new_art = Article . objects . get ( id = 1 )
>> > new_art . headline
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
u ' New headline '
2006-12-30 08:12:02 +08:00
Add some categories and test the many - to - many form output .
>> > new_art . categories . all ( )
[ ]
>> > new_art . categories . add ( Category . objects . get ( name = ' Entertainment ' ) )
>> > new_art . categories . all ( )
[ < Category : Entertainment > ]
2007-12-03 03:29:54 +08:00
>> > class TestArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
2007-12-13 10:48:04 +08:00
>> > f = TestArticleForm ( auto_id = False , instance = new_art )
2006-12-30 08:12:02 +08:00
>> > print f . as_ul ( )
< li > Headline : < input type = " text " name = " headline " value = " New headline " maxlength = " 50 " / > < / li >
2007-09-08 13:09:39 +08:00
< li > Slug : < input type = " text " name = " slug " value = " new-headline " maxlength = " 50 " / > < / li >
2006-12-30 08:12:02 +08:00
< li > Pub date : < input type = " text " name = " pub_date " value = " 1988-01-04 " / > < / li >
< li > Writer : < select name = " writer " >
< option value = " " > - - - - - - - - - < / option >
< option value = " 1 " selected = " selected " > Mike Royko < / option >
< option value = " 2 " > Bob Woodward < / option >
< / select > < / li >
2007-04-09 09:22:45 +08:00
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > Hello . < / textarea > < / li >
2007-04-28 22:18:03 +08: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 >
2006-12-30 08:12:02 +08:00
< li > Categories : < select multiple = " multiple " name = " categories " >
< option value = " 1 " selected = " selected " > Entertainment < / option >
< option value = " 2 " > It & #39;s a test</option>
< option value = " 3 " > Third test < / option >
2007-01-29 06:36:02 +08:00
< / select > Hold down " Control " , or " Command " on a Mac , to select more than one . < / li >
2006-12-30 08:12:02 +08:00
2009-05-02 15:03:33 +08:00
Initial values can be provided for model forms
>> > f = TestArticleForm ( auto_id = False , initial = { ' headline ' : ' Your headline here ' , ' categories ' : [ ' 1 ' , ' 2 ' ] } )
>> > print 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 = " 1 " > Mike Royko < / option >
< option value = " 2 " > Bob Woodward < / option >
< / select > < / li >
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
< li > Status : < select name = " status " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Draft < / option >
< option value = " 2 " > Pending < / option >
< option value = " 3 " > Live < / option >
< / select > < / li >
< li > Categories : < select multiple = " multiple " name = " categories " >
< option value = " 1 " selected = " selected " > Entertainment < / option >
< option value = " 2 " selected = " selected " > It & #39;s a test</option>
< option value = " 3 " > Third test < / option >
< / select > Hold down " Control " , or " Command " on a Mac , to select more than one . < / li >
2007-12-13 10:48:04 +08:00
>> > f = TestArticleForm ( { ' headline ' : u ' New headline ' , ' slug ' : u ' new-headline ' , ' pub_date ' : u ' 1988-01-04 ' ,
. . . ' writer ' : u ' 1 ' , ' article ' : u ' Hello. ' , ' categories ' : [ u ' 1 ' , u ' 2 ' ] } , instance = new_art )
2007-01-28 12:56:54 +08:00
>> > new_art = f . save ( )
>> > new_art . id
1
>> > new_art = Article . objects . get ( id = 1 )
2007-09-15 07:09:05 +08:00
>> > new_art . categories . order_by ( ' name ' )
2007-01-28 12:56:54 +08:00
[ < Category : Entertainment > , < Category : It ' s a test>]
Now , submit form data with no categories . This deletes the existing categories .
2007-12-13 10:48:04 +08:00
>> > f = TestArticleForm ( { ' headline ' : u ' New headline ' , ' slug ' : u ' new-headline ' , ' pub_date ' : u ' 1988-01-04 ' ,
. . . ' writer ' : u ' 1 ' , ' article ' : u ' Hello. ' } , instance = new_art )
2007-01-28 12:56:54 +08:00
>> > new_art = f . save ( )
>> > new_art . id
1
>> > new_art = Article . objects . get ( id = 1 )
>> > new_art . categories . all ( )
[ ]
Create a new article , with categories , via the form .
2007-12-03 03:29:54 +08:00
>> > class ArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
2007-12-13 10:48:04 +08:00
>> > f = ArticleForm ( { ' headline ' : u ' The walrus was Paul ' , ' slug ' : u ' walrus-was-paul ' , ' pub_date ' : u ' 1967-11-01 ' ,
2007-01-28 12:56:54 +08:00
. . . ' writer ' : u ' 1 ' , ' article ' : u ' Test. ' , ' categories ' : [ u ' 1 ' , u ' 2 ' ] } )
>> > new_art = f . save ( )
>> > new_art . id
2
>> > new_art = Article . objects . get ( id = 2 )
2007-09-15 08:19:22 +08:00
>> > new_art . categories . order_by ( ' name ' )
2007-01-28 12:56:54 +08:00
[ < Category : Entertainment > , < Category : It ' s a test>]
Create a new article , with no categories , via the form .
2007-12-03 03:29:54 +08:00
>> > class ArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
2007-12-13 10:48:04 +08:00
>> > f = ArticleForm ( { ' headline ' : u ' The walrus was Paul ' , ' slug ' : u ' walrus-was-paul ' , ' pub_date ' : u ' 1967-11-01 ' ,
2007-01-28 12:56:54 +08:00
. . . ' writer ' : u ' 1 ' , ' article ' : u ' Test. ' } )
>> > new_art = f . save ( )
>> > new_art . id
3
>> > new_art = Article . objects . get ( id = 3 )
>> > new_art . categories . all ( )
[ ]
2007-08-05 15:39:36 +08:00
Create a new article , with categories , via the form , but use commit = False .
The m2m data won ' t be saved until save_m2m() is invoked on the form.
2007-12-03 03:29:54 +08:00
>> > class ArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
2007-12-13 10:48:04 +08:00
>> > f = ArticleForm ( { ' headline ' : u ' The walrus was Paul ' , ' slug ' : ' walrus-was-paul ' , ' pub_date ' : u ' 1967-11-01 ' ,
2007-08-05 15:39:36 +08:00
. . . ' writer ' : u ' 1 ' , ' article ' : u ' Test. ' , ' categories ' : [ u ' 1 ' , u ' 2 ' ] } )
>> > new_art = f . save ( commit = False )
2007-09-15 07:09:05 +08:00
# Manually save the instance
2007-08-05 15:39:36 +08:00
>> > new_art . save ( )
>> > new_art . id
4
# The instance doesn't have m2m data yet
>> > new_art = Article . objects . get ( id = 4 )
>> > new_art . categories . all ( )
[ ]
# Save the m2m data on the form
>> > f . save_m2m ( )
2007-09-15 08:19:22 +08:00
>> > new_art . categories . order_by ( ' name ' )
2007-08-05 15:39:36 +08:00
[ < Category : Entertainment > , < Category : It ' s a test>]
2007-12-03 03:29:54 +08:00
Here , we define a custom ModelForm . Because it happens to have the same fields as
the Category model , we can just call the form ' s save() to apply its changes to an
2007-01-09 13:49:47 +08:00
existing Category instance .
2007-12-03 03:29:54 +08:00
>> > class ShortCategory ( ModelForm ) :
2007-01-09 13:49:47 +08:00
. . . name = CharField ( max_length = 5 )
2007-09-08 13:09:39 +08:00
. . . slug = CharField ( max_length = 5 )
2007-01-09 13:49:47 +08:00
. . . url = CharField ( max_length = 3 )
>> > cat = Category . objects . get ( name = ' Third test ' )
>> > cat
< Category : Third test >
>> > cat . id
3
2007-12-13 10:48:04 +08:00
>> > form = ShortCategory ( { ' name ' : ' Third ' , ' slug ' : ' third ' , ' url ' : ' 3rd ' } , instance = cat )
2007-12-03 03:29:54 +08:00
>> > form . save ( )
2007-01-09 13:49:47 +08:00
< Category : Third >
>> > Category . objects . get ( id = 3 )
< Category : Third >
2007-02-20 10:42:07 +08:00
2007-02-21 13:14:28 +08: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 .
2007-12-03 03:29:54 +08:00
>> > class ArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
2007-12-13 10:48:04 +08:00
>> > f = ArticleForm ( auto_id = False )
2007-02-21 13:14:28 +08:00
>> > print f . as_ul ( )
< li > Headline : < input type = " text " name = " headline " maxlength = " 50 " / > < / li >
2007-09-08 13:09:39 +08:00
< li > Slug : < input type = " text " name = " slug " maxlength = " 50 " / > < / li >
2007-02-21 13:14:28 +08:00
< li > Pub date : < input type = " text " name = " pub_date " / > < / li >
< li > Writer : < select name = " writer " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Mike Royko < / option >
< option value = " 2 " > Bob Woodward < / option >
< / select > < / li >
2007-04-09 09:22:45 +08:00
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
2007-04-28 22:18:03 +08: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 >
2007-02-21 13:14:28 +08:00
< li > Categories : < select multiple = " multiple " name = " categories " >
< option value = " 1 " > Entertainment < / option >
< option value = " 2 " > It & #39;s a test</option>
< option value = " 3 " > Third < / option >
< / select > Hold down " Control " , or " Command " on a Mac , to select more than one . < / li >
>> > Category . objects . create ( name = ' Fourth ' , url = ' 4th ' )
< Category : Fourth >
>> > Writer . objects . create ( name = ' Carl Bernstein ' )
< Writer : Carl Bernstein >
>> > print f . as_ul ( )
< li > Headline : < input type = " text " name = " headline " maxlength = " 50 " / > < / li >
2007-09-08 13:09:39 +08:00
< li > Slug : < input type = " text " name = " slug " maxlength = " 50 " / > < / li >
2007-02-21 13:14:28 +08:00
< li > Pub date : < input type = " text " name = " pub_date " / > < / li >
< li > Writer : < select name = " writer " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Mike Royko < / option >
< option value = " 2 " > Bob Woodward < / option >
< option value = " 3 " > Carl Bernstein < / option >
< / select > < / li >
2007-04-09 09:22:45 +08:00
< li > Article : < textarea rows = " 10 " cols = " 40 " name = " article " > < / textarea > < / li >
2007-04-28 22:18:03 +08: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 >
2007-02-21 13:14:28 +08:00
< li > Categories : < select multiple = " multiple " name = " categories " >
< option value = " 1 " > Entertainment < / option >
< option value = " 2 " > It & #39;s a test</option>
< option value = " 3 " > Third < / option >
< option value = " 4 " > Fourth < / option >
< / select > Hold down " Control " , or " Command " on a Mac , to select more than one . < / li >
2007-02-20 10:42:07 +08:00
# ModelChoiceField ############################################################
2008-07-19 09:22:26 +08:00
>> > from django . forms import ModelChoiceField , ModelMultipleChoiceField
2007-02-20 10:42:07 +08:00
>> > f = ModelChoiceField ( Category . objects . all ( ) )
2007-11-13 22:36:29 +08:00
>> > list ( f . choices )
[ ( u ' ' , u ' --------- ' ) , ( 1 , u ' Entertainment ' ) , ( 2 , u " It ' s a test " ) , ( 3 , u ' Third ' ) , ( 4 , u ' Fourth ' ) ]
2007-02-20 10:42:07 +08:00
>> > f . clean ( ' ' )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' This field is required. ' ]
>> > f . clean ( None )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' This field is required. ' ]
>> > f . clean ( 0 )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. That choice is not one of the available choices. ' ]
>> > f . clean ( 3 )
< Category : Third >
>> > f . clean ( 2 )
< Category : It ' s a test>
2007-02-21 13:14:28 +08: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.
>> > Category . objects . create ( name = ' Fifth ' , url = ' 5th ' )
< Category : Fifth >
>> > f . clean ( 5 )
< Category : Fifth >
# Delete a Category object *after* the ModelChoiceField has already been
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
>> > Category . objects . get ( url = ' 5th ' ) . delete ( )
>> > f . clean ( 5 )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. That choice is not one of the available choices. ' ]
2007-02-20 10:42:07 +08:00
>> > f = ModelChoiceField ( Category . objects . filter ( pk = 1 ) , required = False )
>> > print f . clean ( ' ' )
None
>> > f . clean ( ' ' )
>> > f . clean ( ' 1 ' )
< Category : Entertainment >
2007-02-21 13:14:28 +08:00
>> > f . clean ( ' 100 ' )
2007-02-20 10:42:07 +08:00
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. That choice is not one of the available choices. ' ]
2007-11-13 22:36:29 +08:00
# queryset can be changed after the field is created.
>> > f . queryset = Category . objects . exclude ( name = ' Fourth ' )
>> > list ( f . choices )
[ ( u ' ' , u ' --------- ' ) , ( 1 , u ' Entertainment ' ) , ( 2 , u " It ' s a test " ) , ( 3 , u ' Third ' ) ]
>> > f . clean ( 3 )
< Category : Third >
>> > f . clean ( 4 )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. That choice is not one of the available choices. ' ]
2008-03-20 07:10:45 +08:00
# check that we can safely iterate choices repeatedly
>> > gen_one = list ( f . choices )
>> > gen_two = f . choices
>> > gen_one [ 2 ]
( 2 L , u " It ' s a test " )
>> > list ( gen_two )
[ ( u ' ' , u ' --------- ' ) , ( 1 L , u ' Entertainment ' ) , ( 2 L , u " It ' s a test " ) , ( 3 L , u ' Third ' ) ]
# 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 )
>> > list ( f . choices )
[ ( u ' ' , u ' --------- ' ) , ( 1 L , ' category Entertainment ' ) , ( 2 L , " category It ' s a test " ) , ( 3 L , ' category Third ' ) , ( 4 L , ' category Fourth ' ) ]
2007-11-13 22:36:29 +08:00
2007-02-20 10:42:07 +08:00
# ModelMultipleChoiceField ####################################################
>> > f = ModelMultipleChoiceField ( Category . objects . all ( ) )
2007-11-13 22:36:29 +08:00
>> > list ( f . choices )
[ ( 1 , u ' Entertainment ' ) , ( 2 , u " It ' s a test " ) , ( 3 , u ' Third ' ) , ( 4 , u ' Fourth ' ) ]
2007-02-20 10:42:07 +08:00
>> > f . clean ( None )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' This field is required. ' ]
>> > f . clean ( [ ] )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' This field is required. ' ]
>> > f . clean ( [ 1 ] )
[ < Category : Entertainment > ]
>> > f . clean ( [ 2 ] )
[ < Category : It ' s a test>]
>> > f . clean ( [ ' 1 ' ] )
[ < Category : Entertainment > ]
>> > f . clean ( [ ' 1 ' , ' 2 ' ] )
[ < Category : Entertainment > , < Category : It ' s a test>]
>> > f . clean ( [ 1 , ' 2 ' ] )
[ < Category : Entertainment > , < Category : It ' s a test>]
>> > f . clean ( ( 1 , ' 2 ' ) )
[ < Category : Entertainment > , < Category : It ' s a test>]
2007-02-21 13:14:28 +08:00
>> > f . clean ( [ ' 100 ' ] )
2007-02-20 10:42:07 +08:00
Traceback ( most recent call last ) :
. . .
2007-02-21 13:14:28 +08:00
ValidationError : [ u ' Select a valid choice. 100 is not one of the available choices. ' ]
2007-02-20 10:42:07 +08:00
>> > f . clean ( ' hello ' )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Enter a list of values. ' ]
2009-03-31 07:00:36 +08:00
>> > f . clean ( [ ' fail ' ] )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' " fail " is not a valid value for a primary key. ' ]
2007-02-21 13:14:28 +08:00
2007-11-10 03:35:56 +08:00
# Add a Category object *after* the ModelMultipleChoiceField has already been
2007-02-21 13:14:28 +08:00
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
>> > Category . objects . create ( id = 6 , name = ' Sixth ' , url = ' 6th ' )
< Category : Sixth >
>> > f . clean ( [ 6 ] )
[ < Category : Sixth > ]
2007-11-10 03:35:56 +08:00
# Delete a Category object *after* the ModelMultipleChoiceField has already been
2007-02-21 13:14:28 +08:00
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
>> > Category . objects . get ( url = ' 6th ' ) . delete ( )
>> > f . clean ( [ 6 ] )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. 6 is not one of the available choices. ' ]
2007-02-20 10:42:07 +08:00
>> > f = ModelMultipleChoiceField ( Category . objects . all ( ) , required = False )
>> > f . clean ( [ ] )
[ ]
>> > f . clean ( ( ) )
[ ]
2007-02-21 13:14:28 +08:00
>> > f . clean ( [ ' 10 ' ] )
2007-02-20 10:42:07 +08:00
Traceback ( most recent call last ) :
. . .
2007-02-21 13:14:28 +08:00
ValidationError : [ u ' Select a valid choice. 10 is not one of the available choices. ' ]
>> > f . clean ( [ ' 3 ' , ' 10 ' ] )
2007-02-20 10:42:07 +08:00
Traceback ( most recent call last ) :
. . .
2007-02-21 13:14:28 +08:00
ValidationError : [ u ' Select a valid choice. 10 is not one of the available choices. ' ]
>> > f . clean ( [ ' 1 ' , ' 10 ' ] )
2007-02-20 10:42:07 +08:00
Traceback ( most recent call last ) :
. . .
2007-02-21 13:14:28 +08:00
ValidationError : [ u ' Select a valid choice. 10 is not one of the available choices. ' ]
2007-02-21 13:59:46 +08:00
2007-11-13 22:36:29 +08:00
# queryset can be changed after the field is created.
>> > f . queryset = Category . objects . exclude ( name = ' Fourth ' )
>> > list ( f . choices )
[ ( 1 , u ' Entertainment ' ) , ( 2 , u " It ' s a test " ) , ( 3 , u ' Third ' ) ]
>> > f . clean ( [ 3 ] )
[ < Category : Third > ]
>> > f . clean ( [ 4 ] )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. 4 is not one of the available choices. ' ]
>> > f . clean ( [ ' 3 ' , ' 4 ' ] )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. 4 is not one of the available choices. ' ]
2008-03-20 07:10:45 +08:00
>> > f . queryset = Category . objects . all ( )
>> > f . label_from_instance = lambda obj : " multicategory " + str ( obj )
>> > list ( f . choices )
[ ( 1 L , ' multicategory Entertainment ' ) , ( 2 L , " multicategory It ' s a test " ) , ( 3 L , ' multicategory Third ' ) , ( 4 L , ' multicategory Fourth ' ) ]
2007-11-13 22:36:29 +08:00
2008-08-23 03:27:26 +08:00
# OneToOneField ###############################################################
>> > class ImprovedArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = ImprovedArticle
>> > ImprovedArticleForm . base_fields . keys ( )
[ ' article ' ]
>> > class ImprovedArticleWithParentLinkForm ( ModelForm ) :
. . . class Meta :
. . . model = ImprovedArticleWithParentLink
>> > ImprovedArticleWithParentLinkForm . base_fields . keys ( )
[ ]
2010-01-05 11:56:19 +08:00
>> > bw = BetterWriter ( name = u ' Joe Better ' , score = 10 )
2008-08-25 11:51:25 +08:00
>> > bw . save ( )
>> > sorted ( model_to_dict ( bw ) . keys ( ) )
2010-01-05 11:56:19 +08:00
[ ' id ' , ' name ' , ' score ' , ' writer_ptr ' ]
>> > class BetterWriterForm ( ModelForm ) :
. . . class Meta :
. . . model = BetterWriter
>> > form = BetterWriterForm ( { ' name ' : ' Some Name ' , ' score ' : 12 } )
>> > form . is_valid ( )
True
>> > bw2 = form . save ( )
>> > bw2 . delete ( )
2008-08-31 17:49:55 +08:00
>> > class WriterProfileForm ( ModelForm ) :
. . . class Meta :
. . . model = WriterProfile
>> > form = WriterProfileForm ( )
>> > print form . as_p ( )
< p > < label for = " id_writer " > Writer : < / label > < select name = " writer " id = " id_writer " >
< option value = " " selected = " selected " > - - - - - - - - - < / option >
< option value = " 1 " > Mike Royko < / option >
< option value = " 2 " > Bob Woodward < / option >
< option value = " 3 " > Carl Bernstein < / option >
< option value = " 4 " > Joe Better < / option >
< / select > < / p >
< p > < label for = " id_age " > Age : < / label > < input type = " text " name = " age " id = " id_age " / > < / p >
>> > data = {
. . . ' writer ' : u ' 2 ' ,
. . . ' age ' : u ' 65 ' ,
. . . }
>> > form = WriterProfileForm ( data )
>> > instance = form . save ( )
>> > instance
< WriterProfile : Bob Woodward is 65 >
>> > form = WriterProfileForm ( instance = instance )
>> > print form . as_p ( )
< p > < label for = " id_writer " > Writer : < / label > < select name = " writer " id = " id_writer " >
< option value = " " > - - - - - - - - - < / option >
< option value = " 1 " > Mike Royko < / option >
< option value = " 2 " selected = " selected " > Bob Woodward < / option >
< option value = " 3 " > Carl Bernstein < / option >
< option value = " 4 " > Joe Better < / option >
< / select > < / p >
< p > < label for = " id_age " > Age : < / label > < input type = " text " name = " age " value = " 65 " id = " id_age " / > < / p >
2008-08-25 11:51:25 +08:00
2007-02-21 13:59:46 +08:00
# PhoneNumberField ############################################################
2007-12-03 03:29:54 +08:00
>> > class PhoneNumberForm ( ModelForm ) :
. . . class Meta :
. . . model = PhoneNumber
2007-12-13 10:48:04 +08:00
>> > f = PhoneNumberForm ( { ' phone ' : ' (312) 555-1212 ' , ' description ' : ' Assistance ' } )
2007-02-21 13:59:46 +08:00
>> > f . is_valid ( )
True
2008-03-20 03:11:51 +08:00
>> > f . cleaned_data [ ' phone ' ]
u ' 312-555-1212 '
>> > f . cleaned_data [ ' description ' ]
u ' Assistance '
2008-01-18 02:03:21 +08:00
# FileField ###################################################################
2008-08-09 04:59:02 +08:00
# File forms.
2008-01-18 02:03:21 +08:00
>> > class TextFileForm ( ModelForm ) :
. . . class Meta :
. . . model = TextFile
2008-01-18 23:53:19 +08:00
# Test conditions when files is either not given or empty.
2008-01-18 02:03:21 +08:00
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } )
>> > f . is_valid ( )
False
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , files = { } )
>> > f . is_valid ( )
False
2008-01-18 23:53:19 +08:00
# Upload a file and ensure it all works as expected.
2008-01-18 02:03:21 +08:00
2008-07-01 23:10:51 +08:00
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , files = { ' file ' : SimpleUploadedFile ( ' test1.txt ' , ' hello world ' ) } )
>> > f . is_valid ( )
True
>> > type ( f . cleaned_data [ ' file ' ] )
2008-07-08 07:16:00 +08:00
< class ' django . core . files . uploadedfile . SimpleUploadedFile ' >
2008-07-01 23:10:51 +08:00
>> > instance = f . save ( )
>> > instance . file
2008-08-09 04:59:02 +08:00
< FieldFile : tests / test1 . txt >
2008-07-01 23:10:51 +08:00
2008-08-09 04:59:02 +08:00
>> > instance . file . delete ( )
2008-07-01 23:10:51 +08:00
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , files = { ' file ' : SimpleUploadedFile ( ' test1.txt ' , ' hello world ' ) } )
2008-01-18 02:03:21 +08:00
>> > f . is_valid ( )
True
>> > type ( f . cleaned_data [ ' file ' ] )
2008-07-08 07:16:00 +08:00
< class ' django . core . files . uploadedfile . SimpleUploadedFile ' >
2008-01-18 02:03:21 +08:00
>> > instance = f . save ( )
>> > instance . file
2008-08-09 04:59:02 +08:00
< FieldFile : tests / test1 . txt >
2008-01-18 02:03:21 +08:00
2009-03-31 06:52:16 +08:00
# Check if the max_length attribute has been inherited from the model.
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , files = { ' file ' : SimpleUploadedFile ( ' test-maxlength.txt ' , ' hello world ' ) } )
>> > f . is_valid ( )
False
2008-01-18 23:53:19 +08: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.
2008-01-18 02:03:21 +08:00
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , instance = instance )
>> > f . is_valid ( )
True
>> > f . cleaned_data [ ' file ' ]
2008-08-09 04:59:02 +08:00
< FieldFile : tests / test1 . txt >
2008-01-18 02:03:21 +08:00
>> > instance = f . save ( )
>> > instance . file
2008-08-09 04:59:02 +08:00
< FieldFile : tests / test1 . txt >
2008-01-18 02:03:21 +08:00
2008-01-18 23:53:19 +08:00
# Delete the current file since this is not done by Django.
2008-08-09 04:59:02 +08:00
>> > instance . file . delete ( )
2008-01-18 02:03:21 +08:00
2008-01-18 23:53:19 +08:00
# Override the file by uploading a new one.
2008-01-18 02:03:21 +08:00
2008-07-01 23:10:51 +08:00
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , files = { ' file ' : SimpleUploadedFile ( ' test2.txt ' , ' hello world ' ) } , instance = instance )
2008-01-18 02:03:21 +08:00
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . file
2008-08-09 04:59:02 +08:00
< FieldFile : tests / test2 . txt >
2008-01-18 02:03:21 +08:00
2008-07-01 23:10:51 +08:00
# Delete the current file since this is not done by Django.
2008-08-09 04:59:02 +08:00
>> > instance . file . delete ( )
2008-07-01 23:10:51 +08:00
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , files = { ' file ' : SimpleUploadedFile ( ' test2.txt ' , ' hello world ' ) } )
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . file
2008-08-09 04:59:02 +08:00
< FieldFile : tests / test2 . txt >
2008-07-01 23:10:51 +08:00
# Delete the current file since this is not done by Django.
2008-08-09 04:59:02 +08:00
>> > instance . file . delete ( )
2008-07-01 23:10:51 +08:00
2008-01-18 02:03:21 +08:00
>> > instance . delete ( )
2010-01-12 10:29:45 +08:00
# Test the non-required FileField
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } )
>> > f . fields [ ' file ' ] . required = False
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . file
< FieldFile : None >
2008-07-01 23:10:51 +08:00
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , files = { ' file ' : SimpleUploadedFile ( ' test3.txt ' , ' hello world ' ) } , instance = instance )
2008-01-18 02:03:21 +08:00
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . file
2008-08-09 04:59:02 +08:00
< FieldFile : tests / test3 . txt >
2008-07-01 23:10:51 +08:00
2009-02-17 01:30:12 +08:00
# Instance can be edited w/out re-uploading the file and existing file should be preserved.
>> > f = TextFileForm ( data = { ' description ' : u ' New Description ' } , instance = instance )
>> > f . fields [ ' file ' ] . required = False
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . description
u ' New Description '
>> > instance . file
< FieldFile : tests / test3 . txt >
2008-07-01 23:10:51 +08:00
# Delete the current file since this is not done by Django.
2008-08-09 04:59:02 +08:00
>> > instance . file . delete ( )
2008-07-01 23:10:51 +08:00
>> > instance . delete ( )
>> > f = TextFileForm ( data = { ' description ' : u ' Assistance ' } , files = { ' file ' : SimpleUploadedFile ( ' test3.txt ' , ' hello world ' ) } )
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . file
2008-08-09 04:59:02 +08:00
< FieldFile : tests / test3 . txt >
2008-07-01 23:10:51 +08:00
# Delete the current file since this is not done by Django.
2008-08-09 04:59:02 +08:00
>> > instance . file . delete ( )
2008-01-18 02:03:21 +08:00
>> > instance . delete ( )
2009-12-17 23:10:38 +08:00
# BigIntegerField ################################################################
>> > class BigIntForm ( forms . ModelForm ) :
. . . class Meta :
. . . model = BigInt
2010-01-12 10:29:45 +08:00
. . .
2009-12-17 23:10:38 +08:00
>> > bif = BigIntForm ( { ' biggie ' : ' -9223372036854775808 ' } )
>> > bif . is_valid ( )
True
>> > bif = BigIntForm ( { ' biggie ' : ' -9223372036854775809 ' } )
>> > bif . is_valid ( )
False
>> > bif . errors
{ ' biggie ' : [ u ' Ensure this value is greater than or equal to -9223372036854775808. ' ] }
>> > bif = BigIntForm ( { ' biggie ' : ' 9223372036854775807 ' } )
>> > bif . is_valid ( )
True
>> > bif = BigIntForm ( { ' biggie ' : ' 9223372036854775808 ' } )
>> > bif . is_valid ( )
False
>> > bif . errors
{ ' biggie ' : [ u ' Ensure this value is less than or equal to 9223372036854775807. ' ] }
2009-02-17 02:34:28 +08:00
""" }
2008-01-18 23:53:19 +08:00
2009-02-17 02:34:28 +08:00
if test_images :
__test__ [ ' API_TESTS ' ] + = """
2008-01-18 23:53:19 +08:00
# ImageField ###################################################################
# ImageField and FileField are nearly identical, but they differ slighty when
# it comes to validation. This specifically tests that #6302 is fixed for
# both file fields and image fields.
>> > class ImageFileForm ( ModelForm ) :
. . . class Meta :
. . . model = ImageFile
2008-07-13 04:44:05 +08:00
>> > image_data = open ( os . path . join ( os . path . dirname ( __file__ ) , " test.png " ) , ' rb ' ) . read ( )
2009-02-17 02:34:28 +08:00
>> > image_data2 = open ( os . path . join ( os . path . dirname ( __file__ ) , " test2.png " ) , ' rb ' ) . read ( )
2008-01-18 23:53:19 +08:00
2008-07-01 23:10:51 +08:00
>> > f = ImageFileForm ( data = { ' description ' : u ' An image ' } , files = { ' image ' : SimpleUploadedFile ( ' test.png ' , image_data ) } )
>> > f . is_valid ( )
True
>> > type ( f . cleaned_data [ ' image ' ] )
2008-07-08 07:16:00 +08:00
< class ' django . core . files . uploadedfile . SimpleUploadedFile ' >
2008-07-01 23:10:51 +08:00
>> > instance = f . save ( )
>> > instance . image
2008-09-02 11:07:26 +08:00
< . . . FieldFile : tests / test . png >
2009-02-17 02:34:28 +08:00
>> > instance . width
16
>> > instance . height
16
2008-07-01 23:10:51 +08:00
2009-05-28 13:46:09 +08:00
# 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 )
2008-07-01 23:10:51 +08:00
>> > f = ImageFileForm ( data = { ' description ' : u ' An image ' } , files = { ' image ' : SimpleUploadedFile ( ' test.png ' , image_data ) } )
2008-01-18 23:53:19 +08:00
>> > f . is_valid ( )
True
>> > type ( f . cleaned_data [ ' image ' ] )
2008-07-08 07:16:00 +08:00
< class ' django . core . files . uploadedfile . SimpleUploadedFile ' >
2008-01-18 23:53:19 +08:00
>> > instance = f . save ( )
>> > instance . image
2008-09-02 11:07:26 +08:00
< . . . FieldFile : tests / test . png >
2009-02-17 02:34:28 +08:00
>> > instance . width
16
>> > instance . height
16
2008-01-18 23:53:19 +08:00
2009-02-17 02:34:28 +08:00
# Edit an instance that already has the (required) image defined in the model. This will not
2008-01-18 23:53:19 +08:00
# save the image again, but leave it exactly as it is.
>> > f = ImageFileForm ( data = { ' description ' : u ' Look, it changed ' } , instance = instance )
>> > f . is_valid ( )
True
>> > f . cleaned_data [ ' image ' ]
2008-09-02 11:07:26 +08:00
< . . . FieldFile : tests / test . png >
2008-01-18 23:53:19 +08:00
>> > instance = f . save ( )
>> > instance . image
2008-09-02 11:07:26 +08:00
< . . . FieldFile : tests / test . png >
2009-02-17 02:34:28 +08:00
>> > instance . height
16
>> > instance . width
16
2008-01-18 23:53:19 +08:00
2009-05-28 13:46:09 +08:00
# 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 )
2008-01-18 23:53:19 +08:00
# Override the file by uploading a new one.
2009-02-17 02:34:28 +08:00
>> > f = ImageFileForm ( data = { ' description ' : u ' Changed it ' } , files = { ' image ' : SimpleUploadedFile ( ' test2.png ' , image_data2 ) } , instance = instance )
2008-07-01 23:10:51 +08:00
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . image
2008-09-02 11:07:26 +08:00
< . . . FieldFile : tests / test2 . png >
2009-02-17 02:34:28 +08:00
>> > instance . height
32
>> > instance . width
48
2008-07-01 23:10:51 +08:00
2009-05-28 13:46:09 +08:00
# 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 )
2008-07-01 23:10:51 +08:00
>> > instance . delete ( )
2009-02-17 02:34:28 +08:00
>> > f = ImageFileForm ( data = { ' description ' : u ' Changed it ' } , files = { ' image ' : SimpleUploadedFile ( ' test2.png ' , image_data2 ) } )
2008-01-18 23:53:19 +08:00
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . image
2008-09-02 11:07:26 +08:00
< . . . FieldFile : tests / test2 . png >
2009-02-17 02:34:28 +08:00
>> > instance . height
32
>> > instance . width
48
2008-01-18 23:53:19 +08:00
2009-05-28 13:46:09 +08:00
# 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 )
2008-01-18 23:53:19 +08:00
>> > instance . delete ( )
# Test the non-required ImageField
2009-02-17 02:34:28 +08:00
>> > class OptionalImageFileForm ( ModelForm ) :
. . . class Meta :
. . . model = OptionalImageFile
>> > f = OptionalImageFileForm ( data = { ' description ' : u ' Test ' } )
2008-01-18 23:53:19 +08:00
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . image
2008-09-02 11:07:26 +08:00
< . . . FieldFile : None >
2009-02-17 02:34:28 +08:00
>> > instance . width
>> > instance . height
2008-01-18 23:53:19 +08:00
2009-02-17 02:34:28 +08:00
>> > f = OptionalImageFileForm ( data = { ' description ' : u ' And a final one ' } , files = { ' image ' : SimpleUploadedFile ( ' test3.png ' , image_data ) } , instance = instance )
2008-07-01 23:10:51 +08:00
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . image
2008-09-02 11:07:26 +08:00
< . . . FieldFile : tests / test3 . png >
2009-02-17 02:34:28 +08:00
>> > instance . width
16
>> > instance . height
16
# Editing the instance without re-uploading the image should not affect the image or its width/height properties
>> > f = OptionalImageFileForm ( data = { ' description ' : u ' New Description ' } , instance = instance )
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . description
u ' New Description '
>> > instance . image
< . . . FieldFile : tests / test3 . png >
>> > instance . width
16
>> > instance . height
16
2008-07-01 23:10:51 +08:00
# Delete the current file since this is not done by Django.
2008-08-09 04:59:02 +08:00
>> > instance . image . delete ( )
2008-07-01 23:10:51 +08:00
>> > instance . delete ( )
2009-02-17 02:34:28 +08:00
>> > f = OptionalImageFileForm ( data = { ' description ' : u ' And a final one ' } , files = { ' image ' : SimpleUploadedFile ( ' test4.png ' , image_data2 ) } )
2008-01-18 23:53:19 +08:00
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . image
2009-02-17 02:34:28 +08:00
< . . . FieldFile : tests / test4 . png >
>> > instance . width
48
>> > instance . height
32
2008-01-18 23:53:19 +08:00
>> > instance . delete ( )
2008-11-05 03:48:35 +08:00
# Test callable upload_to behavior that's dependent on the value of another field in the model
>> > f = ImageFileForm ( data = { ' description ' : u ' And a final one ' , ' path ' : ' foo ' } , files = { ' image ' : SimpleUploadedFile ( ' test4.png ' , image_data ) } )
>> > f . is_valid ( )
True
>> > instance = f . save ( )
>> > instance . image
< . . . FieldFile : foo / test4 . png >
>> > instance . delete ( )
2009-02-17 02:34:28 +08:00
"""
__test__ [ ' API_TESTS ' ] + = """
2008-11-05 03:48:35 +08:00
2008-07-19 07:54:34 +08:00
# Media on a ModelForm ########################################################
# Similar to a regular Form class you can define custom media to be used on
# the ModelForm.
>> > class ModelFormWithMedia ( ModelForm ) :
. . . class Media :
. . . js = ( ' /some/form/javascript ' , )
. . . css = {
. . . ' all ' : ( ' /some/form/css ' , )
. . . }
. . . class Meta :
. . . model = PhoneNumber
>> > f = ModelFormWithMedia ( )
>> > print f . media
< link href = " /some/form/css " type = " text/css " media = " all " rel = " stylesheet " / >
< script type = " text/javascript " src = " /some/form/javascript " > < / script >
2008-08-29 04:58:10 +08:00
>> > class CommaSeparatedIntegerForm ( ModelForm ) :
. . . class Meta :
. . . model = CommaSeparatedInteger
2010-01-05 11:56:19 +08:00
>> > f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,2,3 ' } )
>> > f . is_valid ( )
True
>> > f . cleaned_data
{ ' field ' : u ' 1,2,3 ' }
>> > f = CommaSeparatedIntegerForm ( { ' field ' : ' 1a,2 ' } )
>> > f . errors
{ ' field ' : [ u ' Enter only digits separated by commas. ' ] }
>> > f = CommaSeparatedIntegerForm ( { ' field ' : ' ,,,, ' } )
>> > f . is_valid ( )
True
>> > f . cleaned_data
{ ' field ' : u ' ,,,, ' }
>> > f = CommaSeparatedIntegerForm ( { ' field ' : ' 1.2 ' } )
>> > f . errors
{ ' field ' : [ u ' Enter only digits separated by commas. ' ] }
>> > f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,a,2 ' } )
>> > f . errors
{ ' field ' : [ u ' Enter only digits separated by commas. ' ] }
>> > f = CommaSeparatedIntegerForm ( { ' field ' : ' 1,,2 ' } )
>> > f . is_valid ( )
True
>> > f . cleaned_data
{ ' field ' : u ' 1,,2 ' }
>> > f = CommaSeparatedIntegerForm ( { ' field ' : ' 1 ' } )
>> > f . is_valid ( )
True
>> > f . cleaned_data
{ ' field ' : u ' 1 ' }
2008-08-29 04:58:10 +08:00
2008-09-02 03:08:08 +08:00
# unique/unique_together validation
2008-09-01 04:11:11 +08:00
2008-09-02 03:08:08 +08:00
>> > class ProductForm ( ModelForm ) :
. . . class Meta :
. . . model = Product
>> > form = ProductForm ( { ' slug ' : ' teddy-bear-blue ' } )
>> > form . is_valid ( )
True
>> > obj = form . save ( )
>> > obj
< Product : teddy - bear - blue >
>> > form = ProductForm ( { ' slug ' : ' teddy-bear-blue ' } )
>> > form . is_valid ( )
False
>> > form . _errors
{ ' slug ' : [ u ' Product with this Slug already exists. ' ] }
>> > form = ProductForm ( { ' slug ' : ' teddy-bear-blue ' } , instance = obj )
>> > form . is_valid ( )
True
# ModelForm test of unique_together constraint
>> > class PriceForm ( ModelForm ) :
. . . class Meta :
. . . model = Price
>> > form = PriceForm ( { ' price ' : ' 6.00 ' , ' quantity ' : ' 1 ' } )
>> > form . is_valid ( )
True
>> > form . save ( )
< Price : 1 for 6.00 >
>> > form = PriceForm ( { ' price ' : ' 6.00 ' , ' quantity ' : ' 1 ' } )
>> > form . is_valid ( )
False
>> > form . _errors
{ ' __all__ ' : [ u ' Price with this Price and Quantity already exists. ' ] }
2010-01-12 10:29:45 +08:00
This Price instance generated by this form is not valid because the quantity
field is required , but the form is valid because the field is excluded from
the form . This is for backwards compatibility .
2008-09-02 22:20:11 +08:00
>> > class PriceForm ( ModelForm ) :
. . . class Meta :
. . . model = Price
. . . exclude = ( ' quantity ' , )
>> > form = PriceForm ( { ' price ' : ' 6.00 ' } )
>> > form . is_valid ( )
2010-01-12 10:29:45 +08:00
True
>> > price = form . save ( commit = False )
>> > price . full_clean ( )
2010-01-05 11:56:19 +08:00
Traceback ( most recent call last ) :
. . .
2010-01-12 10:29:45 +08:00
ValidationError : { ' quantity ' : [ u ' This field cannot be null. ' ] }
The form should not validate fields that it doesn ' t contain even if they are
specified using ' fields ' , not ' exclude ' .
. . . class Meta :
. . . model = Price
. . . fields = ( ' price ' , )
>> > form = PriceForm ( { ' price ' : ' 6.00 ' } )
>> > form . is_valid ( )
True
The form should still have an instance of a model that is not complete and
not saved into a DB yet .
>> > form . instance . price
Decimal ( ' 6.00 ' )
>> > form . instance . quantity is None
True
>> > form . instance . pk is None
True
2008-09-02 22:20:11 +08:00
2008-10-21 22:04:24 +08:00
# Unique & unique together with null values
2009-03-15 13:05:26 +08:00
>> > class BookForm ( ModelForm ) :
. . . class Meta :
2008-10-21 22:04:24 +08:00
. . . model = Book
>> > w = Writer . objects . get ( name = ' Mike Royko ' )
>> > form = BookForm ( { ' title ' : ' I May Be Wrong But I Doubt It ' , ' author ' : w . pk } )
>> > form . is_valid ( )
True
>> > form . save ( )
< Book : Book object >
>> > form = BookForm ( { ' title ' : ' I May Be Wrong But I Doubt It ' , ' author ' : w . pk } )
>> > form . is_valid ( )
False
>> > form . _errors
{ ' __all__ ' : [ u ' Book with this Title and Author already exists. ' ] }
>> > form = BookForm ( { ' title ' : ' I May Be Wrong But I Doubt It ' } )
>> > form . is_valid ( )
True
>> > form . save ( )
< Book : Book object >
>> > form = BookForm ( { ' title ' : ' I May Be Wrong But I Doubt It ' } )
>> > form . is_valid ( )
True
2008-11-06 03:47:44 +08:00
# Test for primary_key being in the form and failing validation.
>> > class ExplicitPKForm ( ModelForm ) :
. . . class Meta :
. . . model = ExplicitPK
. . . fields = ( ' key ' , ' desc ' , )
>> > form = ExplicitPKForm ( { ' key ' : u ' ' , ' desc ' : u ' ' } )
>> > form . is_valid ( )
False
# Ensure keys and blank character strings are tested for uniqueness.
>> > form = ExplicitPKForm ( { ' key ' : u ' key1 ' , ' desc ' : u ' ' } )
>> > form . is_valid ( )
True
>> > form . save ( )
< ExplicitPK : key1 >
>> > form = ExplicitPKForm ( { ' key ' : u ' key1 ' , ' desc ' : u ' ' } )
>> > form . is_valid ( )
False
2009-01-23 12:53:18 +08:00
>> > sorted ( form . errors . items ( ) )
[ ( ' __all__ ' , [ u ' Explicit pk with this Key and Desc already exists. ' ] ) , ( ' desc ' , [ u ' Explicit pk with this Desc already exists. ' ] ) , ( ' key ' , [ u ' Explicit pk with this Key already exists. ' ] ) ]
2008-11-06 03:47:44 +08:00
2008-09-02 03:08:08 +08:00
# Choices on CharField and IntegerField
2008-09-01 04:11:11 +08:00
>> > class ArticleForm ( ModelForm ) :
. . . class Meta :
. . . model = Article
>> > f = ArticleForm ( )
>> > f . fields [ ' status ' ] . clean ( ' 42 ' )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. 42 is not one of the available choices. ' ]
>> > class ArticleStatusForm ( ModelForm ) :
. . . class Meta :
. . . model = ArticleStatus
>> > f = ArticleStatusForm ( )
>> > f . fields [ ' status ' ] . clean ( ' z ' )
Traceback ( most recent call last ) :
. . .
ValidationError : [ u ' Select a valid choice. z is not one of the available choices. ' ]
2008-09-02 06:43:38 +08:00
# Foreign keys which use to_field #############################################
>> > apple = Inventory . objects . create ( barcode = 86 , name = ' Apple ' )
>> > pear = Inventory . objects . create ( barcode = 22 , name = ' Pear ' )
>> > core = Inventory . objects . create ( barcode = 87 , name = ' Core ' , parent = apple )
>> > field = ModelChoiceField ( Inventory . objects . all ( ) , to_field_name = ' barcode ' )
>> > for choice in field . choices :
. . . print choice
( u ' ' , u ' --------- ' )
( 86 , u ' Apple ' )
( 22 , u ' Pear ' )
( 87 , u ' Core ' )
>> > class InventoryForm ( ModelForm ) :
. . . class Meta :
. . . model = Inventory
>> > form = InventoryForm ( instance = core )
>> > print form [ ' parent ' ]
< select name = " parent " id = " id_parent " >
< option value = " " > - - - - - - - - - < / option >
< option value = " 86 " selected = " selected " > Apple < / option >
< option value = " 22 " > Pear < / option >
< option value = " 87 " > Core < / option >
< / select >
>> > data = model_to_dict ( core )
>> > data [ ' parent ' ] = ' 22 '
>> > form = InventoryForm ( data = data , instance = core )
>> > core = form . save ( )
>> > core . parent
< Inventory : Pear >
2008-10-11 06:13:16 +08:00
2009-03-17 18:30:17 +08:00
>> > class CategoryForm ( ModelForm ) :
. . . description = forms . CharField ( )
. . . class Meta :
. . . model = Category
. . . fields = [ ' description ' , ' url ' ]
>> > CategoryForm . base_fields . keys ( )
[ ' description ' , ' url ' ]
>> > print CategoryForm ( )
< tr > < th > < label for = " id_description " > Description : < / label > < / th > < td > < input type = " text " name = " description " id = " id_description " / > < / 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 >
2009-04-30 21:47:39 +08:00
### Validation on unique_for_date
>> > p = Post . objects . create ( title = " Django 1.0 is released " , slug = " Django 1.0 " , subtitle = " Finally " , posted = datetime . date ( 2008 , 9 , 3 ) )
>> > class PostForm ( ModelForm ) :
. . . class Meta :
. . . model = Post
>> > f = PostForm ( { ' title ' : " Django 1.0 is released " , ' posted ' : ' 2008-09-03 ' } )
>> > f . is_valid ( )
False
>> > f . errors
{ ' title ' : [ u ' Title must be unique for Posted date. ' ] }
>> > f = PostForm ( { ' title ' : " Work on Django 1.1 begins " , ' posted ' : ' 2008-09-03 ' } )
>> > f . is_valid ( )
True
>> > f = PostForm ( { ' title ' : " Django 1.0 is released " , ' posted ' : ' 2008-09-04 ' } )
>> > f . is_valid ( )
True
>> > f = PostForm ( { ' slug ' : " Django 1.0 " , ' posted ' : ' 2008-01-01 ' } )
>> > f . is_valid ( )
False
>> > f . errors
{ ' slug ' : [ u ' Slug must be unique for Posted year. ' ] }
>> > f = PostForm ( { ' subtitle ' : " Finally " , ' posted ' : ' 2008-09-30 ' } )
>> > f . is_valid ( )
False
>> > f . errors
{ ' subtitle ' : [ u ' Subtitle must be unique for Posted month. ' ] }
>> > f = PostForm ( { ' subtitle ' : " Finally " , " title " : " Django 1.0 is released " , " slug " : " Django 1.0 " , ' posted ' : ' 2008-09-03 ' } , instance = p )
>> > f . is_valid ( )
True
2008-10-11 06:13:16 +08:00
# Clean up
>> > import shutil
>> > shutil . rmtree ( temp_storage_dir )
2009-02-17 02:34:28 +08:00
"""