2 XX. Generating HTML forms from models
4 This is mostly just a reworking of the form_for_model/form_for_instance tests
5 to use ModelForm. As such, the text may not make sense in all cases, and the
6 examples are probably a poor fit for the ModelForm syntax. In other words,
7 most of these tests should be rewritten.
13 from django
.db
import models
21 class Category(models
.Model
):
22 name
= models
.CharField(max_length
=20)
23 slug
= models
.SlugField(max_length
=20)
24 url
= models
.CharField('The URL', max_length
=40)
26 def __unicode__(self
):
29 class Writer(models
.Model
):
30 name
= models
.CharField(max_length
=50, help_text
='Use both first and last names.')
32 def __unicode__(self
):
35 class Article(models
.Model
):
36 headline
= models
.CharField(max_length
=50)
37 slug
= models
.SlugField()
38 pub_date
= models
.DateField()
39 created
= models
.DateField(editable
=False)
40 writer
= models
.ForeignKey(Writer
)
41 article
= models
.TextField()
42 categories
= models
.ManyToManyField(Category
, blank
=True)
43 status
= models
.IntegerField(choices
=ARTICLE_STATUS
, blank
=True, null
=True)
48 self
.created
= datetime
.date
.today()
49 return super(Article
, self
).save()
51 def __unicode__(self
):
54 class PhoneNumber(models
.Model
):
55 phone
= models
.PhoneNumberField()
56 description
= models
.CharField(max_length
=20)
58 def __unicode__(self
):
61 class TextFile(models
.Model
):
62 description
= models
.CharField(max_length
=20)
63 file = models
.FileField(upload_to
=tempfile
.gettempdir())
65 def __unicode__(self
):
66 return self
.description
68 class ImageFile(models
.Model
):
69 description
= models
.CharField(max_length
=20)
71 # If PIL is available, try testing PIL.
72 # Otherwise, it's equivalent to TextFile above.
74 image
= models
.ImageField(upload_to
=tempfile
.gettempdir())
76 image
= models
.FileField(upload_to
=tempfile
.gettempdir())
78 def __unicode__(self
):
79 return self
.description
81 __test__
= {'API_TESTS': """
82 >>> from django import forms
83 >>> from django.forms.models import ModelForm
84 >>> from django.core.files.uploadedfile import SimpleUploadedFile
86 The bare bones, absolutely nothing custom, basic case.
88 >>> class CategoryForm(ModelForm):
91 >>> CategoryForm.base_fields.keys()
92 ['name', 'slug', 'url']
97 >>> class CategoryForm(ModelForm):
98 ... some_extra_field = forms.BooleanField()
103 >>> CategoryForm.base_fields.keys()
104 ['name', 'slug', 'url', 'some_extra_field']
109 >>> class CategoryForm(ModelForm):
110 ... url = forms.BooleanField()
115 >>> CategoryForm.base_fields['url'].__class__
116 <class 'django.forms.fields.BooleanField'>
121 >>> class CategoryForm(ModelForm):
127 >>> CategoryForm.base_fields.keys()
133 >>> class CategoryForm(ModelForm):
137 ... exclude = ['url']
139 >>> CategoryForm.base_fields.keys()
143 Using 'fields' *and* 'exclude'. Not sure why you'd want to do this, but uh,
144 "be liberal in what you accept" and all.
146 >>> class CategoryForm(ModelForm):
150 ... fields = ['name', 'url']
151 ... exclude = ['url']
153 >>> CategoryForm.base_fields.keys()
156 Don't allow more than one 'model' definition in the inheritance hierarchy.
157 Technically, it would generate a valid form, but the fact that the resulting
158 save method won't deal with multiple objects is likely to trip up people not
159 familiar with the mechanics.
161 >>> class CategoryForm(ModelForm):
165 >>> class OddForm(CategoryForm):
169 OddForm is now an Article-related thing, because BadForm.Meta overrides
171 >>> OddForm.base_fields.keys()
172 ['headline', 'slug', 'pub_date', 'writer', 'article', 'status', 'categories']
174 >>> class ArticleForm(ModelForm):
178 First class with a Meta class wins.
180 >>> class BadForm(ArticleForm, CategoryForm):
182 >>> OddForm.base_fields.keys()
183 ['headline', 'slug', 'pub_date', 'writer', 'article', 'status', 'categories']
185 Subclassing without specifying a Meta on the class will use the parent's Meta
186 (or the first parent in the MRO if there are multiple parent classes).
188 >>> class CategoryForm(ModelForm):
191 >>> class SubCategoryForm(CategoryForm):
193 >>> SubCategoryForm.base_fields.keys()
194 ['name', 'slug', 'url']
196 We can also subclass the Meta inner class to change the fields list.
198 >>> class CategoryForm(ModelForm):
199 ... checkbox = forms.BooleanField()
203 >>> class SubCategoryForm(CategoryForm):
204 ... class Meta(CategoryForm.Meta):
205 ... exclude = ['url']
207 >>> print SubCategoryForm()
208 <tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
209 <tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
210 <tr><th><label for="id_checkbox">Checkbox:</label></th><td><input type="checkbox" name="checkbox" id="id_checkbox" /></td></tr>
212 # Old form_for_x tests #######################################################
214 >>> from django.forms import ModelForm, CharField
217 >>> Category.objects.all()
220 >>> class CategoryForm(ModelForm):
223 >>> f = CategoryForm()
225 <tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
226 <tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
227 <tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>
229 <li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" maxlength="20" /></li>
230 <li><label for="id_slug">Slug:</label> <input id="id_slug" type="text" name="slug" maxlength="20" /></li>
231 <li><label for="id_url">The URL:</label> <input id="id_url" type="text" name="url" maxlength="40" /></li>
233 <input id="id_name" type="text" name="name" maxlength="20" />
235 >>> f = CategoryForm(auto_id=False)
237 <li>Name: <input type="text" name="name" maxlength="20" /></li>
238 <li>Slug: <input type="text" name="slug" maxlength="20" /></li>
239 <li>The URL: <input type="text" name="url" maxlength="40" /></li>
241 >>> f = CategoryForm({'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'})
244 >>> f.cleaned_data['url']
246 >>> f.cleaned_data['name']
248 >>> f.cleaned_data['slug']
252 <Category: Entertainment>
253 >>> Category.objects.all()
254 [<Category: Entertainment>]
256 >>> f = CategoryForm({'name': "It's a test", 'slug': 'its-test', 'url': 'test'})
259 >>> f.cleaned_data['url']
261 >>> f.cleaned_data['name']
263 >>> f.cleaned_data['slug']
267 <Category: It's a test>
268 >>> Category.objects.order_by('name')
269 [<Category: Entertainment>, <Category: It's a test>]
271 If you call save() with commit=False, then it will return an object that
272 hasn't yet been saved to the database. In this case, it's up to you to call
273 save() on the resulting model instance.
274 >>> f = CategoryForm({'name': 'Third test', 'slug': 'third-test', 'url': 'third'})
277 >>> f.cleaned_data['url']
279 >>> f.cleaned_data['name']
281 >>> f.cleaned_data['slug']
283 >>> obj = f.save(commit=False)
285 <Category: Third test>
286 >>> Category.objects.order_by('name')
287 [<Category: Entertainment>, <Category: It's a test>]
289 >>> Category.objects.order_by('name')
290 [<Category: Entertainment>, <Category: It's a test>, <Category: Third test>]
292 If you call save() with invalid data, you'll get a ValueError.
293 >>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'})
295 [u'This field is required.']
297 [u'This field is required.']
299 Traceback (most recent call last):
301 AttributeError: 'CategoryForm' object has no attribute 'cleaned_data'
303 Traceback (most recent call last):
305 ValueError: The Category could not be created because the data didn't validate.
306 >>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'})
308 Traceback (most recent call last):
310 ValueError: The Category could not be created because the data didn't validate.
312 Create a couple of Writers.
313 >>> w = Writer(name='Mike Royko')
315 >>> w = Writer(name='Bob Woodward')
318 ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any
319 fields with the 'choices' attribute are represented by a ChoiceField.
320 >>> class ArticleForm(ModelForm):
323 >>> f = ArticleForm(auto_id=False)
325 <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
326 <tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" /></td></tr>
327 <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
328 <tr><th>Writer:</th><td><select name="writer">
329 <option value="" selected="selected">---------</option>
330 <option value="1">Mike Royko</option>
331 <option value="2">Bob Woodward</option>
333 <tr><th>Article:</th><td><textarea rows="10" cols="40" name="article"></textarea></td></tr>
334 <tr><th>Status:</th><td><select name="status">
335 <option value="" selected="selected">---------</option>
336 <option value="1">Draft</option>
337 <option value="2">Pending</option>
338 <option value="3">Live</option>
340 <tr><th>Categories:</th><td><select multiple="multiple" name="categories">
341 <option value="1">Entertainment</option>
342 <option value="2">It's a test</option>
343 <option value="3">Third test</option>
344 </select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr>
346 You can restrict a form to a subset of the complete list of fields
347 by providing a 'fields' argument. If you try to save a
348 model created with such a form, you need to ensure that the fields
349 that are _not_ on the form have default values, or are allowed to have
350 a value of None. If a field isn't specified on a form, the object created
351 from the form can't provide a value for that field!
352 >>> class PartialArticleForm(ModelForm):
355 ... fields = ('headline','pub_date')
356 >>> f = PartialArticleForm(auto_id=False)
358 <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
359 <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
361 Use form_for_instance to create a Form from a model instance. The difference
362 between this Form and one created via form_for_model is that the object's
363 current values are inserted as 'initial' data in each Field.
364 >>> w = Writer.objects.get(name='Mike Royko')
365 >>> class RoykoForm(ModelForm):
368 >>> f = RoykoForm(auto_id=False, instance=w)
370 <tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr>
372 >>> art = Article(headline='Test article', slug='test-article', pub_date=datetime.date(1988, 1, 4), writer=w, article='Hello.')
376 >>> class TestArticleForm(ModelForm):
379 >>> f = TestArticleForm(auto_id=False, instance=art)
381 <li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li>
382 <li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" /></li>
383 <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
384 <li>Writer: <select name="writer">
385 <option value="">---------</option>
386 <option value="1" selected="selected">Mike Royko</option>
387 <option value="2">Bob Woodward</option>
389 <li>Article: <textarea rows="10" cols="40" name="article">Hello.</textarea></li>
390 <li>Status: <select name="status">
391 <option value="" selected="selected">---------</option>
392 <option value="1">Draft</option>
393 <option value="2">Pending</option>
394 <option value="3">Live</option>
396 <li>Categories: <select multiple="multiple" name="categories">
397 <option value="1">Entertainment</option>
398 <option value="2">It's a test</option>
399 <option value="3">Third test</option>
400 </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
401 >>> f = TestArticleForm({'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}, instance=art)
404 >>> test_art = f.save()
407 >>> test_art = Article.objects.get(id=1)
408 >>> test_art.headline
411 You can create a form over a subset of the available fields
412 by specifying a 'fields' argument to form_for_instance.
413 >>> class PartialArticleForm(ModelForm):
416 ... fields=('headline', 'slug', 'pub_date')
417 >>> f = PartialArticleForm({'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False, instance=art)
419 <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
420 <li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
421 <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
424 >>> new_art = f.save()
427 >>> new_art = Article.objects.get(id=1)
431 Add some categories and test the many-to-many form output.
432 >>> new_art.categories.all()
434 >>> new_art.categories.add(Category.objects.get(name='Entertainment'))
435 >>> new_art.categories.all()
436 [<Category: Entertainment>]
437 >>> class TestArticleForm(ModelForm):
440 >>> f = TestArticleForm(auto_id=False, instance=new_art)
442 <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
443 <li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
444 <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
445 <li>Writer: <select name="writer">
446 <option value="">---------</option>
447 <option value="1" selected="selected">Mike Royko</option>
448 <option value="2">Bob Woodward</option>
450 <li>Article: <textarea rows="10" cols="40" name="article">Hello.</textarea></li>
451 <li>Status: <select name="status">
452 <option value="" selected="selected">---------</option>
453 <option value="1">Draft</option>
454 <option value="2">Pending</option>
455 <option value="3">Live</option>
457 <li>Categories: <select multiple="multiple" name="categories">
458 <option value="1" selected="selected">Entertainment</option>
459 <option value="2">It's a test</option>
460 <option value="3">Third test</option>
461 </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
463 >>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
464 ... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}, instance=new_art)
465 >>> new_art = f.save()
468 >>> new_art = Article.objects.get(id=1)
469 >>> new_art.categories.order_by('name')
470 [<Category: Entertainment>, <Category: It's a test>]
472 Now, submit form data with no categories. This deletes the existing categories.
473 >>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
474 ... 'writer': u'1', 'article': u'Hello.'}, instance=new_art)
475 >>> new_art = f.save()
478 >>> new_art = Article.objects.get(id=1)
479 >>> new_art.categories.all()
482 Create a new article, with categories, via the form.
483 >>> class ArticleForm(ModelForm):
486 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
487 ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
488 >>> new_art = f.save()
491 >>> new_art = Article.objects.get(id=2)
492 >>> new_art.categories.order_by('name')
493 [<Category: Entertainment>, <Category: It's a test>]
495 Create a new article, with no categories, via the form.
496 >>> class ArticleForm(ModelForm):
499 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
500 ... 'writer': u'1', 'article': u'Test.'})
501 >>> new_art = f.save()
504 >>> new_art = Article.objects.get(id=3)
505 >>> new_art.categories.all()
508 Create a new article, with categories, via the form, but use commit=False.
509 The m2m data won't be saved until save_m2m() is invoked on the form.
510 >>> class ArticleForm(ModelForm):
513 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01',
514 ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
515 >>> new_art = f.save(commit=False)
517 # Manually save the instance
522 # The instance doesn't have m2m data yet
523 >>> new_art = Article.objects.get(id=4)
524 >>> new_art.categories.all()
527 # Save the m2m data on the form
529 >>> new_art.categories.order_by('name')
530 [<Category: Entertainment>, <Category: It's a test>]
532 Here, we define a custom ModelForm. Because it happens to have the same fields as
533 the Category model, we can just call the form's save() to apply its changes to an
534 existing Category instance.
535 >>> class ShortCategory(ModelForm):
536 ... name = CharField(max_length=5)
537 ... slug = CharField(max_length=5)
538 ... url = CharField(max_length=3)
539 >>> cat = Category.objects.get(name='Third test')
541 <Category: Third test>
544 >>> form = ShortCategory({'name': 'Third', 'slug': 'third', 'url': '3rd'}, instance=cat)
547 >>> Category.objects.get(id=3)
550 Here, we demonstrate that choices for a ForeignKey ChoiceField are determined
551 at runtime, based on the data in the database when the form is displayed, not
552 the data in the database when the form is instantiated.
553 >>> class ArticleForm(ModelForm):
556 >>> f = ArticleForm(auto_id=False)
558 <li>Headline: <input type="text" name="headline" maxlength="50" /></li>
559 <li>Slug: <input type="text" name="slug" maxlength="50" /></li>
560 <li>Pub date: <input type="text" name="pub_date" /></li>
561 <li>Writer: <select name="writer">
562 <option value="" selected="selected">---------</option>
563 <option value="1">Mike Royko</option>
564 <option value="2">Bob Woodward</option>
566 <li>Article: <textarea rows="10" cols="40" name="article"></textarea></li>
567 <li>Status: <select name="status">
568 <option value="" selected="selected">---------</option>
569 <option value="1">Draft</option>
570 <option value="2">Pending</option>
571 <option value="3">Live</option>
573 <li>Categories: <select multiple="multiple" name="categories">
574 <option value="1">Entertainment</option>
575 <option value="2">It's a test</option>
576 <option value="3">Third</option>
577 </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
578 >>> Category.objects.create(name='Fourth', url='4th')
580 >>> Writer.objects.create(name='Carl Bernstein')
581 <Writer: Carl Bernstein>
583 <li>Headline: <input type="text" name="headline" maxlength="50" /></li>
584 <li>Slug: <input type="text" name="slug" maxlength="50" /></li>
585 <li>Pub date: <input type="text" name="pub_date" /></li>
586 <li>Writer: <select name="writer">
587 <option value="" selected="selected">---------</option>
588 <option value="1">Mike Royko</option>
589 <option value="2">Bob Woodward</option>
590 <option value="3">Carl Bernstein</option>
592 <li>Article: <textarea rows="10" cols="40" name="article"></textarea></li>
593 <li>Status: <select name="status">
594 <option value="" selected="selected">---------</option>
595 <option value="1">Draft</option>
596 <option value="2">Pending</option>
597 <option value="3">Live</option>
599 <li>Categories: <select multiple="multiple" name="categories">
600 <option value="1">Entertainment</option>
601 <option value="2">It's a test</option>
602 <option value="3">Third</option>
603 <option value="4">Fourth</option>
604 </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
606 # ModelChoiceField ############################################################
608 >>> from django.forms import ModelChoiceField, ModelMultipleChoiceField
610 >>> f = ModelChoiceField(Category.objects.all())
612 [(u'', u'---------'), (1, u'Entertainment'), (2, u"It's a test"), (3, u'Third'), (4, u'Fourth')]
614 Traceback (most recent call last):
616 ValidationError: [u'This field is required.']
618 Traceback (most recent call last):
620 ValidationError: [u'This field is required.']
622 Traceback (most recent call last):
624 ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
628 <Category: It's a test>
630 # Add a Category object *after* the ModelChoiceField has already been
631 # instantiated. This proves clean() checks the database during clean() rather
632 # than caching it at time of instantiation.
633 >>> Category.objects.create(name='Fifth', url='5th')
638 # Delete a Category object *after* the ModelChoiceField has already been
639 # instantiated. This proves clean() checks the database during clean() rather
640 # than caching it at time of instantiation.
641 >>> Category.objects.get(url='5th').delete()
643 Traceback (most recent call last):
645 ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
647 >>> f = ModelChoiceField(Category.objects.filter(pk=1), required=False)
648 >>> print f.clean('')
652 <Category: Entertainment>
654 Traceback (most recent call last):
656 ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
658 # queryset can be changed after the field is created.
659 >>> f.queryset = Category.objects.exclude(name='Fourth')
661 [(u'', u'---------'), (1, u'Entertainment'), (2, u"It's a test"), (3, u'Third')]
665 Traceback (most recent call last):
667 ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
669 # check that we can safely iterate choices repeatedly
670 >>> gen_one = list(f.choices)
671 >>> gen_two = f.choices
675 [(u'', u'---------'), (1L, u'Entertainment'), (2L, u"It's a test"), (3L, u'Third')]
677 # check that we can override the label_from_instance method to print custom labels (#4620)
678 >>> f.queryset = Category.objects.all()
679 >>> f.label_from_instance = lambda obj: "category " + str(obj)
681 [(u'', u'---------'), (1L, 'category Entertainment'), (2L, "category It's a test"), (3L, 'category Third'), (4L, 'category Fourth')]
683 # ModelMultipleChoiceField ####################################################
685 >>> f = ModelMultipleChoiceField(Category.objects.all())
687 [(1, u'Entertainment'), (2, u"It's a test"), (3, u'Third'), (4, u'Fourth')]
689 Traceback (most recent call last):
691 ValidationError: [u'This field is required.']
693 Traceback (most recent call last):
695 ValidationError: [u'This field is required.']
697 [<Category: Entertainment>]
699 [<Category: It's a test>]
701 [<Category: Entertainment>]
702 >>> f.clean(['1', '2'])
703 [<Category: Entertainment>, <Category: It's a test>]
704 >>> f.clean([1, '2'])
705 [<Category: Entertainment>, <Category: It's a test>]
706 >>> f.clean((1, '2'))
707 [<Category: Entertainment>, <Category: It's a test>]
709 Traceback (most recent call last):
711 ValidationError: [u'Select a valid choice. 100 is not one of the available choices.']
713 Traceback (most recent call last):
715 ValidationError: [u'Enter a list of values.']
717 # Add a Category object *after* the ModelMultipleChoiceField has already been
718 # instantiated. This proves clean() checks the database during clean() rather
719 # than caching it at time of instantiation.
720 >>> Category.objects.create(id=6, name='Sixth', url='6th')
725 # Delete a Category object *after* the ModelMultipleChoiceField has already been
726 # instantiated. This proves clean() checks the database during clean() rather
727 # than caching it at time of instantiation.
728 >>> Category.objects.get(url='6th').delete()
730 Traceback (most recent call last):
732 ValidationError: [u'Select a valid choice. 6 is not one of the available choices.']
734 >>> f = ModelMultipleChoiceField(Category.objects.all(), required=False)
740 Traceback (most recent call last):
742 ValidationError: [u'Select a valid choice. 10 is not one of the available choices.']
743 >>> f.clean(['3', '10'])
744 Traceback (most recent call last):
746 ValidationError: [u'Select a valid choice. 10 is not one of the available choices.']
747 >>> f.clean(['1', '10'])
748 Traceback (most recent call last):
750 ValidationError: [u'Select a valid choice. 10 is not one of the available choices.']
752 # queryset can be changed after the field is created.
753 >>> f.queryset = Category.objects.exclude(name='Fourth')
755 [(1, u'Entertainment'), (2, u"It's a test"), (3, u'Third')]
759 Traceback (most recent call last):
761 ValidationError: [u'Select a valid choice. 4 is not one of the available choices.']
762 >>> f.clean(['3', '4'])
763 Traceback (most recent call last):
765 ValidationError: [u'Select a valid choice. 4 is not one of the available choices.']
767 >>> f.queryset = Category.objects.all()
768 >>> f.label_from_instance = lambda obj: "multicategory " + str(obj)
770 [(1L, 'multicategory Entertainment'), (2L, "multicategory It's a test"), (3L, 'multicategory Third'), (4L, 'multicategory Fourth')]
772 # PhoneNumberField ############################################################
774 >>> class PhoneNumberForm(ModelForm):
776 ... model = PhoneNumber
777 >>> f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'})
780 >>> f.cleaned_data['phone']
782 >>> f.cleaned_data['description']
785 # FileField ###################################################################
787 >>> class TextFileForm(ModelForm):
791 # Test conditions when files is either not given or empty.
793 >>> f = TextFileForm(data={'description': u'Assistance'})
796 >>> f = TextFileForm(data={'description': u'Assistance'}, files={})
800 # Upload a file and ensure it all works as expected.
802 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test1.txt', 'hello world')})
805 >>> type(f.cleaned_data['file'])
806 <class 'django.core.files.uploadedfile.SimpleUploadedFile'>
807 >>> instance = f.save()
811 >>> os.unlink(instance.get_file_filename())
813 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test1.txt', 'hello world')})
816 >>> type(f.cleaned_data['file'])
817 <class 'django.core.files.uploadedfile.SimpleUploadedFile'>
818 >>> instance = f.save()
822 # Edit an instance that already has the file defined in the model. This will not
823 # save the file again, but leave it exactly as it is.
825 >>> f = TextFileForm(data={'description': u'Assistance'}, instance=instance)
828 >>> f.cleaned_data['file']
830 >>> instance = f.save()
834 # Delete the current file since this is not done by Django.
835 >>> os.unlink(instance.get_file_filename())
837 # Override the file by uploading a new one.
839 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test2.txt', 'hello world')}, instance=instance)
842 >>> instance = f.save()
846 # Delete the current file since this is not done by Django.
847 >>> os.unlink(instance.get_file_filename())
849 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test2.txt', 'hello world')})
852 >>> instance = f.save()
856 # Delete the current file since this is not done by Django.
857 >>> os.unlink(instance.get_file_filename())
859 >>> instance.delete()
861 # Test the non-required FileField
863 >>> f = TextFileForm(data={'description': u'Assistance'})
864 >>> f.fields['file'].required = False
867 >>> instance = f.save()
871 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}, instance=instance)
874 >>> instance = f.save()
878 # Delete the current file since this is not done by Django.
879 >>> os.unlink(instance.get_file_filename())
880 >>> instance.delete()
882 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')})
885 >>> instance = f.save()
889 # Delete the current file since this is not done by Django.
890 >>> os.unlink(instance.get_file_filename())
891 >>> instance.delete()
893 # ImageField ###################################################################
895 # ImageField and FileField are nearly identical, but they differ slighty when
896 # it comes to validation. This specifically tests that #6302 is fixed for
897 # both file fields and image fields.
899 >>> class ImageFileForm(ModelForm):
901 ... model = ImageFile
903 >>> image_data = open(os.path.join(os.path.dirname(__file__), "test.png"), 'rb').read()
905 >>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)})
908 >>> type(f.cleaned_data['image'])
909 <class 'django.core.files.uploadedfile.SimpleUploadedFile'>
910 >>> instance = f.save()
914 # Delete the current file since this is not done by Django.
915 >>> os.unlink(instance.get_image_filename())
917 >>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)})
920 >>> type(f.cleaned_data['image'])
921 <class 'django.core.files.uploadedfile.SimpleUploadedFile'>
922 >>> instance = f.save()
926 # Edit an instance that already has the image defined in the model. This will not
927 # save the image again, but leave it exactly as it is.
929 >>> f = ImageFileForm(data={'description': u'Look, it changed'}, instance=instance)
932 >>> f.cleaned_data['image']
934 >>> instance = f.save()
938 # Delete the current image since this is not done by Django.
940 >>> os.unlink(instance.get_image_filename())
942 # Override the file by uploading a new one.
944 >>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data)}, instance=instance)
947 >>> instance = f.save()
951 # Delete the current file since this is not done by Django.
952 >>> os.unlink(instance.get_image_filename())
953 >>> instance.delete()
955 >>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data)})
958 >>> instance = f.save()
962 # Delete the current file since this is not done by Django.
963 >>> os.unlink(instance.get_image_filename())
964 >>> instance.delete()
966 # Test the non-required ImageField
968 >>> f = ImageFileForm(data={'description': u'Test'})
969 >>> f.fields['image'].required = False
972 >>> instance = f.save()
976 >>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}, instance=instance)
979 >>> instance = f.save()
983 # Delete the current file since this is not done by Django.
984 >>> os.unlink(instance.get_image_filename())
985 >>> instance.delete()
987 >>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)})
990 >>> instance = f.save()
993 >>> instance.delete()
995 # Media on a ModelForm ########################################################
997 # Similar to a regular Form class you can define custom media to be used on
1000 >>> class ModelFormWithMedia(ModelForm):
1002 ... js = ('/some/form/javascript',)
1004 ... 'all': ('/some/form/css',)
1007 ... model = PhoneNumber
1008 >>> f = ModelFormWithMedia()
1010 <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />
1011 <script type="text/javascript" src="/some/form/javascript"></script>