Django

Code

root/django/branches/multiple-db-support/docs/forms.txt

Revision 4158, 26.0 kB (checked in by jpellerin, 2 years ago)

[multi-db] Merged trunk to [4100]. Some tests still failing.

Line 
1 ===============================
2 Forms, fields, and manipulators
3 ===============================
4
5 Once you've got a chance to play with Django's admin interface, you'll probably
6 wonder if the fantastic form validation framework it uses is available to user
7 code. It is, and this document explains how the framework works.
8
9     .. admonition:: A note to the lazy
10
11         If all you want to do is present forms for a user to create and/or
12         update a given object, you may be able to use `generic views`_.
13
14 We'll take a top-down approach to examining Django's form validation framework,
15 because much of the time you won't need to use the lower-level APIs. Throughout
16 this document, we'll be working with the following model, a "place" object::
17
18     from django.db import models
19
20     PLACE_TYPES = (
21         (1, 'Bar'),
22         (2, 'Restaurant'),
23         (3, 'Movie Theater'),
24         (4, 'Secret Hideout'),
25     )
26
27     class Place(models.Model):
28         name = models.CharField(maxlength=100)
29         address = models.CharField(maxlength=100, blank=True)
30         city = models.CharField(maxlength=50, blank=True)
31         state = models.USStateField()
32         zip_code = models.CharField(maxlength=5, blank=True)
33         place_type = models.IntegerField(choices=PLACE_TYPES)
34
35         class Admin:
36             pass
37
38         def __str__(self):
39             return self.name
40
41 Defining the above class is enough to create an admin interface to a ``Place``,
42 but what if you want to allow public users to submit places?
43
44 Manipulators
45 ============
46
47 The highest-level interface for object creation and modification is the
48 **Manipulator** framework. A manipulator is a utility class tied to a given
49 model that "knows" how to create or modify instances of that model and how to
50 validate data for the object. Manipulators come in two flavors:
51 ``AddManipulators`` and ``ChangeManipulators``. Functionally they are quite
52 similar, but the former knows how to create new instances of the model, while
53 the latter modifies existing instances. Both types of classes are automatically
54 created when you define a new class::
55
56     >>> from mysite.myapp.models import Place
57     >>> Place.AddManipulator
58     <class 'django.models.manipulators.AddManipulator'>
59     >>> Place.ChangeManipulator
60     <class 'django.models.manipulators.ChangeManipulator'>
61
62 Using the ``AddManipulator``
63 ----------------------------
64
65 We'll start with the ``AddManipulator``.  Here's a very simple view that takes
66 POSTed data from the browser and creates a new ``Place`` object::
67
68     from django.shortcuts import render_to_response
69     from django.http import Http404, HttpResponse, HttpResponseRedirect
70     from django import forms
71     from mysite.myapp.models import Place
72
73     def naive_create_place(request):
74         """A naive approach to creating places; don't actually use this!"""
75         # Create the AddManipulator.
76         manipulator = Place.AddManipulator()
77
78         # Make a copy of the POSTed data so that do_html2python can
79         # modify it in place (request.POST is immutable).
80         new_data = request.POST.copy()
81
82         # Convert the request data (which will all be strings) into the
83         # appropriate Python types for those fields.
84         manipulator.do_html2python(new_data)
85
86         # Save the new object.
87         new_place = manipulator.save(new_data)
88
89         # It worked!
90         return HttpResponse("Place created: %s" % new_place)
91
92 The ``naive_create_place`` example works, but as you probably can tell, this
93 view has a number of problems:
94
95     * No validation of any sort is performed. If, for example, the ``name`` field
96       isn't given in ``request.POST``, the save step will cause a database error
97       because that field is required. Ugly.
98
99     * Even if you *do* perform validation, there's still no way to give that
100       information to the user in any sort of useful way.
101
102     * You'll have to separately create a form (and view) that submits to this
103       page, which is a pain and is redundant.
104
105 Let's dodge these problems momentarily to take a look at how you could create a
106 view with a form that submits to this flawed creation view::
107
108     def naive_create_place_form(request):
109         """Simplistic place form view; don't actually use anything like this!"""
110         # Create a FormWrapper object that the template can use. Ignore
111         # the last two arguments to FormWrapper for now.
112         form = forms.FormWrapper(Place.AddManipulator(), {}, {})
113         return render_to_response('places/naive_create_form.html', {'form': form})
114
115 (This view, as well as all the following ones, has the same imports as in the
116 first example above.)
117
118 The ``forms.FormWrapper`` object is a wrapper that templates can
119 easily deal with to create forms. Here's the ``naive_create_form.html``
120 template::
121
122     {% extends "base.html" %}
123
124     {% block content %}
125     <h1>Create a place:</h1>
126
127     <form method="post" action="../do_new/">
128     <p><label for="id_name">Name:</label> {{ form.name }}</p>
129     <p><label for="id_address">Address:</label> {{ form.address }}</p>
130     <p><label for="id_city">City:</label> {{ form.city }}</p>
131     <p><label for="id_state">State:</label> {{ form.state }}</p>
132     <p><label for="id_zip_code">Zip:</label> {{ form.zip_code }}</p>
133     <p><label for="id_place_type">Place type:</label> {{ form.place_type }}</p>
134     <input type="submit" />
135     </form>
136     {% endblock %}
137
138 Before we get back to the problems with these naive set of views, let's go over
139 some salient points of the above template:
140
141     * Field "widgets" are handled for you: ``{{ form.field }}`` automatically
142       creates the "right" type of widget for the form, as you can see with the
143       ``place_type`` field above.
144
145     * There isn't a way just to spit out the form. You'll still need to define
146       how the form gets laid out. This is a feature: Every form should be
147       designed differently. Django doesn't force you into any type of mold.
148       If you must use tables, use tables. If you're a semantic purist, you can
149       probably find better HTML than in the above template.
150
151     * To avoid name conflicts, the ``id`` values of form elements take the
152       form "id_*fieldname*".
153
154 By creating a creation form we've solved problem number 3 above, but we still
155 don't have any validation. Let's revise the validation issue by writing a new
156 creation view that takes validation into account::
157
158     def create_place_with_validation(request):
159         manipulator = Place.AddManipulator()
160         new_data = request.POST.copy()
161
162         # Check for validation errors
163         errors = manipulator.get_validation_errors(new_data)
164         if errors:
165             return render_to_response('places/errors.html', {'errors': errors})
166         else:
167             manipulator.do_html2python(new_data)
168             new_place = manipulator.save(new_data)
169             return HttpResponse("Place created: %s" % new_place)
170
171 In this new version, errors will be found -- ``manipulator.get_validation_errors``
172 handles all the validation for you -- and those errors can be nicely presented
173 on an error page (templated, of course)::
174
175     {% extends "base.html" %}
176
177     {% block content %}
178
179     <h1>Please go back and correct the following error{{ errors|pluralize }}:</h1>
180     <ul>
181         {% for e in errors.items %}
182         <li>Field "{{ e.0 }}": {{ e.1|join:", " }}</li>
183         {% endfor %}
184     </ul>
185
186     {% endblock %}
187
188 Still, this has its own problems:
189
190     * There's still the issue of creating a separate (redundant) view for the
191       submission form.
192
193     * Errors, though nicely presented, are on a separate page, so the user will
194       have to use the "back" button to fix errors. That's ridiculous and unusable.
195
196 The best way to deal with these issues is to collapse the two views -- the form
197 and the submission -- into a single view.  This view will be responsible for
198 creating the form, validating POSTed data, and creating the new object (if the
199 data is valid). An added bonus of this approach is that errors and the form will
200 both be available on the same page, so errors with fields can be presented in
201 context.
202
203 .. admonition:: Philosophy:
204
205     Finally, for the HTTP purists in the audience (and the authorship), this
206     nicely matches the "true" meanings of HTTP GET and HTTP POST: GET fetches
207     the form, and POST creates the new object.
208
209 Below is the finished view::
210
211     def create_place(request):
212         manipulator = Place.AddManipulator()
213
214         if request.method == 'POST':
215             # If data was POSTed, we're trying to create a new Place.
216             new_data = request.POST.copy()
217
218             # Check for errors.
219             errors = manipulator.get_validation_errors(new_data)
220
221             if not errors:
222                 # No errors. This means we can save the data!
223                 manipulator.do_html2python(new_data)
224                 new_place = manipulator.save(new_data)
225
226                 # Redirect to the object's "edit" page. Always use a redirect
227                 # after POST data, so that reloads don't accidently create
228                 # duplicate entires, and so users don't see the confusing
229                 # "Repost POST data?" alert box in their browsers.
230                 return HttpResponseRedirect("/places/edit/%i/" % new_place.id)
231         else:
232             # No POST, so we want a brand new form without any data or errors.
233             errors = new_data = {}
234
235         # Create the FormWrapper, template, context, response.
236         form = forms.FormWrapper(manipulator, new_data, errors)
237         return render_to_response('places/create_form.html', {'form': form})
238
239 and here's the ``create_form`` template::
240
241     {% extends "base.html" %}
242
243     {% block content %}
244     <h1>Create a place:</h1>
245
246     {% if form.has_errors %}
247     <h2>Please correct the following error{{ form.error_dict|pluralize }}:</h2>
248     {% endif %}
249
250     <form method="post" action=".">
251     <p>
252         <label for="id_name">Name:</label> {{ form.name }}
253         {% if form.name.errors %}*** {{ form.name.errors|join:", " }}{% endif %}
254     </p>
255     <p>
256         <label for="id_address">Address:</label> {{ form.address }}
257         {% if form.address.errors %}*** {{ form.address.errors|join:", " }}{% endif %}
258     </p>
259     <p>
260         <label for="id_city">City:</label> {{ form.city }}
261         {% if form.city.errors %}*** {{ form.city.errors|join:", " }}{% endif %}
262     </p>
263     <p>
264         <label for="id_state">State:</label> {{ form.state }}
265         {% if form.state.errors %}*** {{ form.state.errors|join:", " }}{% endif %}
266     </p>
267     <p>
268         <label for="id_zip_code">Zip:</label> {{ form.zip_code }}
269         {% if form.zip_code.errors %}*** {{ form.zip_code.errors|join:", " }}{% endif %}
270     </p>
271     <p>
272         <label for="id_place_type">Place type:</label> {{ form.place_type }}
273         {% if form.place_type.errors %}*** {{ form.place_type.errors|join:", " }}{% endif %}
274     </p>
275     <input type="submit" />
276     </form>
277     {% endblock %}
278
279 The second two arguments to ``FormWrapper`` (``new_data`` and ``errors``)
280 deserve some mention.
281
282 The first is any "default" data to be used as values for the fields. Pulling
283 the data from ``request.POST``, as is done above, makes sure that if there are
284 errors, the values the user put in aren't lost. If you try the above example,
285 you'll see this in action.
286
287 The second argument is the error list retrieved from
288 ``manipulator.get_validation_errors``.  When passed into the ``FormWrapper``,
289 this gives each field an ``errors`` item (which is a list of error messages
290 associated with the field) as well as a ``html_error_list`` item, which is a
291 ``<ul>`` of error messages. The above template uses these error items to
292 display a simple error message next to each field. The error list is saved as
293 an ``error_dict`` attribute of the ``FormWrapper`` object.
294
295 Using the ``ChangeManipulator``
296 -------------------------------
297
298 The above has covered using the ``AddManipulator`` to create a new object. What
299 about editing an existing one? It's shockingly similar to creating a new one::
300
301     def edit_place(request, place_id):
302         # Get the place in question from the database and create a
303         # ChangeManipulator at the same time.
304         try:
305             manipulator = Place.ChangeManipulator(place_id)
306         except Place.DoesNotExist:
307             raise Http404
308
309         # Grab the Place object in question for future use.
310         place = manipulator.original_object
311
312         if request.method == 'POST':
313             new_data = request.POST.copy()
314             errors = manipulator.get_validation_errors(new_data)
315             if not errors:
316                 manipulator.do_html2python(new_data)
317                 manipulator.save(new_data)
318
319                 # Do a post-after-redirect so that reload works, etc.
320                 return HttpResponseRedirect("/places/edit/%i/" % place.id)
321         else:
322             errors = {}
323             # This makes sure the form accurate represents the fields of the place.
324             new_data = manipulator.flatten_data()
325
326         form = forms.FormWrapper(manipulator, new_data, errors)
327         return render_to_response('places/edit_form.html', {'form': form, 'place': place})
328
329 The only real differences are:
330
331     * We create a ``ChangeManipulator`` instead of an ``AddManipulator``.
332       The argument to a ``ChangeManipulator`` is the ID of the object
333       to be changed. As you can see, the initializer will raise an
334       ``ObjectDoesNotExist`` exception if the ID is invalid.
335
336     * ``ChangeManipulator.original_object`` stores the instance of the
337       object being edited.
338
339     * We set ``new_data`` based upon ``flatten_data()`` from the manipulator.
340       ``flatten_data()`` takes the data from the original object under
341       manipulation, and converts it into a data dictionary that can be used
342       to populate form elements with the existing values for the object.
343
344     * The above example uses a different template, so create and edit can be
345       "skinned" differently if needed, but the form chunk itself is completely
346       identical to the one in the create form above.
347
348 The astute programmer will notice the add and create functions are nearly
349 identical and could in fact be collapsed into a single view. This is left as an
350 exercise for said programmer.
351
352 (However, the even-more-astute programmer will take heed of the note at the top
353 of this document and check out the `generic views`_ documentation if all she
354 wishes to do is this type of simple create/update.)
355
356 Custom forms and manipulators
357 =============================
358
359 All the above is fine and dandy if you just want to use the automatically
360 created manipulators. But the coolness doesn't end there: You can easily create
361 your own custom manipulators for handling custom forms.
362
363 Custom manipulators are pretty simple. Here's a manipulator that you might use
364 for a "contact" form on a website::
365
366     from django import forms
367
368     urgency_choices = (
369         (1, "Extremely urgent"),
370         (2, "Urgent"),
371         (3, "Normal"),
372         (4, "Unimportant"),
373     )
374
375     class ContactManipulator(forms.Manipulator):
376         def __init__(self):
377             self.fields = (
378                 forms.EmailField(field_name="from", is_required=True),
379                 forms.TextField(field_name="subject", length=30, maxlength=200, is_required=True),
380                 forms.SelectField(field_name="urgency", choices=urgency_choices),
381                 forms.LargeTextField(field_name="contents", is_required=True),
382             )
383
384 A certain similarity to Django's models should be apparent. The only required
385 method of a custom manipulator is ``__init__`` which must define the fields
386 present in the manipulator.  See the ``django.forms`` module for
387 all the form fields provided by Django.
388
389 You use this custom manipulator exactly as you would use an auto-generated one.
390 Here's a simple function that might drive the above form::
391
392     def contact_form(request):
393         manipulator = ContactManipulator()
394         if request.method == 'POST':
395             new_data = request.POST.copy()
396             errors = manipulator.get_validation_errors(new_data)
397             if not errors:
398                 manipulator.do_html2python(new_data)
399
400                 # Send e-mail using new_data here...
401
402                 return HttpResponseRedirect("/contact/thankyou/")
403         else:
404             errors = new_data = {}
405         form = forms.FormWrapper(manipulator, new_data, errors)
406         return render_to_response('contact_form.html', {'form': form})
407
408 ``FileField`` and ``ImageField`` special cases
409 ==============================================
410
411 Dealing with ``FileField`` and ``ImageField`` objects is a little more
412 complicated.
413
414 First, you'll need to make sure that your ``<form>`` element correctly defines
415 the ``enctype`` as ``"multipart/form-data"``, in order to upload files::
416
417   <form enctype="multipart/form-data" method="post" action="/foo/">
418
419 Next, you'll need to treat the field in the template slightly differently. A
420 ``FileField`` or ``ImageField`` is represented by *two* HTML form elements.
421
422 For example, given this field in a model::
423
424    photo = model.ImageField('/path/to/upload/location')
425
426 You'd need to display two formfields in the template::
427
428    <p><label for="id_photo">Photo:</label> {{ form.photo }}{{ form.photo_file }}</p>
429
430 The first bit (``{{ form.photo }}``) displays the currently-selected file,
431 while the second (``{{ form.photo_file }}``) actually contains the file upload
432 form field. Thus, at the validation layer you need to check the ``photo_file``
433 key.
434
435 Finally, in your view, make sure to access ``request.FILES``, rather than
436 ``request.POST``, for the uploaded files. This is necessary because
437 ``request.POST`` does not contain file-upload data.
438
439 For example, following the ``new_data`` convention, you might do something like
440 this::
441
442    new_data = request.POST.copy()
443    new_data.update(request.FILES)
444
445 Validators
446 ==========
447
448 One useful feature of manipulators is the automatic validation. Validation is
449 done using a simple validation API: A validator is a callable that raises a
450 ``ValidationError`` if there's something wrong with the data.
451 ``django.core.validators`` defines a host of validator functions (see below),
452 but defining your own couldn't be easier::
453
454     from django.core import validators
455     from django import forms
456
457     class ContactManipulator(forms.Manipulator):
458         def __init__(self):
459             self.fields = (
460                 # ... snip fields as above ...
461                 forms.EmailField(field_name="to", validator_list=[self.isValidToAddress])
462             )
463
464         def isValidToAddress(self, field_data, all_data):
465             if not field_data.endswith("@example.com"):
466                 raise validators.ValidationError("You can only send messages to example.com e-mail addresses.")
467
468 Above, we've added a "to" field to the contact form, but required that the "to"
469 address end with "@example.com" by adding the ``isValidToAddress`` validator to
470 the field's ``validator_list``.
471
472 The arguments to a validator function take a little explanation.  ``field_data``
473 is the value of the field in question, and ``all_data`` is a dictionary of all
474 the data being validated.
475
476 .. admonition:: Note::
477
478     At the point validators are called all data will still be
479     strings (as ``do_html2python`` hasn't been called yet).
480
481 Also, because consistency in user interfaces is important, we strongly urge you
482 to put punctuation at the end of your validation messages.
483
484 When are validators called?
485 ---------------------------
486
487 After a form has been submitted, Django first checks to see that all the
488 required fields are present and non-empty. For each field that passes that
489 test *and if the form submission contained data* for that field, all the
490 validators for that field are called in turn. The emphasized portion in the
491 last sentence is important: if a form field is not submitted (because it
492 contains no data -- which is normal HTML behavior), the validators are not
493 run against the field.
494
495 This feature is particularly important for models using
496 ``models.BooleanField`` or custom manipulators using things like
497 ``forms.CheckBoxField``. If the checkbox is not selected, it will not
498 contribute to the form submission.
499
500 If you would like your validator to run *always*, regardless of whether its
501 attached field contains any data, set the ``always_test`` attribute on the
502 validator function. For example::
503
504     def my_custom_validator(field_data, all_data):
505         # ...
506     my_custom_validator.always_test = True
507
508 This validator will always be executed for any field it is attached to.
509
510 Ready-made validators
511 ---------------------
512
513 Writing your own validator is not difficult, but there are some situations
514 that come up over and over again. Django comes with a number of validators
515 that can be used directly in your code. All of these functions and classes
516 reside in ``django/core/validators.py``.
517
518 The following validators should all be self-explanatory. Each one provides a
519 check for the given property:
520
521     * isAlphaNumeric
522     * isAlphaNumericURL
523     * isSlug
524     * isLowerCase
525     * isUpperCase
526     * isCommaSeparatedIntegerList
527     * isCommaSeparatedEmailList
528     * isValidIPAddress4
529     * isNotEmpty
530     * isOnlyDigits
531     * isNotOnlyDigits
532     * isInteger
533     * isOnlyLetters
534     * isValidANSIDate
535     * isValidANSITime
536     * isValidEmail
537     * isValidImage
538     * isValidImageURL
539     * isValidPhone
540     * isValidQuicktimeVideoURL
541     * isValidURL
542     * isValidHTML
543     * isWellFormedXml
544     * isWellFormedXmlFragment
545     * isExistingURL
546     * isValidUSState
547     * hasNoProfanities
548
549 There are also a group of validators that are slightly more flexible. For
550 these validators, you create a validator instance, passing in the parameters
551 described below. The returned object is a callable that can be used as a
552 validator.
553
554 For example::
555
556     from django.core import validators
557     from django import forms
558
559     power_validator = validators.IsAPowerOf(2)
560
561     class InstallationManipulator(forms.Manipulator)
562         def __init__(self):
563             self.fields = (
564                 ...
565                 forms.IntegerField(field_name = "size", validator_list=[power_validator])
566             )
567
568 Here, ``validators.IsAPowerOf(...)`` returned something that could be used as
569 a validator (in this case, a check that a number was a power of 2).
570
571 Each of the standard validators that take parameters have an optional final
572 argument (``error_message``) that is the message returned when validation
573 fails. If no message is passed in, a default message is used.
574
575 ``AlwaysMatchesOtherField``
576     Takes a field name and the current field is valid if and only if its value
577     matches the contents of the other field.
578
579 ``ValidateIfOtherFieldEquals``
580     Takes three parameters: ``other_field``, ``other_value`` and
581     ``validator_list``, in that order. If ``other_field`` has a value of
582     ``other_value``, then the validators in ``validator_list`` are all run
583     against the current field.
584
585 ``RequiredIfOtherFieldNotGiven``
586     Takes the name of the other field and this field is only required if the
587     other field has no value.
588
589 ``RequiredIfOtherFieldsNotGiven``
590     Similar to ``RequiredIfOtherFieldNotGiven``, except that it takes a list
591     of field names and if any one of the supplied fields does not have a value
592     provided, the field being validated is required.
593
594 ``RequiredIfOtherFieldEquals`` and ``RequiredIfOtherFieldDoesNotEqual``
595     Each of these validator classes takes a field name and a value (in that
596     order). If the given field does (or does not have, in the latter case) the
597     given value, then the current field being validated is required.
598
599     Note that because validators are called before any ``do_html2python()``
600     functions, the value being compared against is a string. So
601     ``RequiredIfOtherFieldEquals('choice', '1')`` is correct, whilst
602     ``RequiredIfOtherFieldEquals('choice', 1)`` will never result in the
603     equality test succeeding.
604
605 ``IsLessThanOtherField``
606     Takes a field name and validates that the current field being validated
607     has a value that is less than (or equal to) the other field's value.
608     Again, comparisons are done using strings, so be cautious about using
609     this function to compare data that should be treated as another type. The
610     string "123" is less than the string "2", for example. If you don't want
611     string comparison here, you will need to write your own validator.
612
613 ``NumberIsInRange``
614     Takes two boundary numbers, ``lower`` and ``upper``, and checks that the
615     field is greater than ``lower`` (if given) and less than ``upper`` (if
616     given). 
617    
618     Both checks are inclusive. That is, ``NumberIsInRange(10, 20)`` will allow
619     values of both 10 and 20. This validator only checks numeric values
620     (e.g., float and integer values).
621
622 ``IsAPowerOf``
623     Takes an integer argument and when called as a validator, checks that the
624     field being validated is a power of the integer.
625
626 ``IsValidFloat``
627     Takes a maximum number of digits and number of decimal places (in that
628     order) and validates whether the field is a float with less than the
629     maximum number of digits and decimal place.
630
631 ``MatchesRegularExpression``
632     Takes a regular expression (a string) as a parameter and validates the
633     field value against it.
634
635 ``AnyValidator``
636     Takes a list of validators as a parameter. At validation time, if the
637     field successfully validates against any one of the validators, it passes
638     validation. The validators are tested in the order specified in the
639     original list.
640
641 ``URLMimeTypeCheck``
642     Used to validate URL fields. Takes a list of MIME types (such as
643     ``text/plain``) at creation time. At validation time, it verifies that the
644     field is indeed a URL and then tries to retrieve the content at the URL.
645     Validation succeeds if the content could be retrieved and it has a content
646     type from the list used to create the validator.
647
648 ``RelaxNGCompact``
649     Used to validate an XML document against a Relax NG compact schema. Takes
650     a file path to the location of the schema and an optional root element
651     (which is wrapped around the XML fragment before validation, if supplied).
652     At validation time, the XML fragment is validated against the schema using
653     the executable specified in the ``JING_PATH`` setting (see the settings_
654     document for more details).
655
656 .. _`generic views`: http://www.djangoproject.com/documentation/generic_views/
657 .. _`models API`: http://www.djangoproject.com/documentation/model_api/
658 .. _settings: http://www.djangoproject.com/documentation/settings/
Note: See TracBrowser for help on using the browser.