diff options
| author | Jacob Kaplan-Moss <jacob@jacobian.org> | 2008-08-23 22:25:40 +0000 |
|---|---|---|
| committer | Jacob Kaplan-Moss <jacob@jacobian.org> | 2008-08-23 22:25:40 +0000 |
| commit | 97cb07c3a10ff0e584a260a7ee1001614691eb1d (patch) | |
| tree | 204f4382c51e1c288dbf547875161731661733f5 /docs/ref/forms | |
| parent | b3688e81943d6d059d3f3c95095498a5aab84852 (diff) | |
Massive reorganization of the docs. See the new docs online at http://docs.djangoproject.com/.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8506 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs/ref/forms')
| -rw-r--r-- | docs/ref/forms/api.txt | 688 | ||||
| -rw-r--r-- | docs/ref/forms/fields.txt | 751 | ||||
| -rw-r--r-- | docs/ref/forms/index.txt | 14 | ||||
| -rw-r--r-- | docs/ref/forms/validation.txt | 109 | ||||
| -rw-r--r-- | docs/ref/forms/widgets.txt | 156 |
5 files changed, 1718 insertions, 0 deletions
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt new file mode 100644 index 0000000000..f8d8a9940a --- /dev/null +++ b/docs/ref/forms/api.txt @@ -0,0 +1,688 @@ +.. _ref-forms-api: + +============= +The Forms API +============= + +.. currentmodule:: django.forms + +.. admonition:: About this document + + This document covers the gritty details of Django's forms API. You should + read the :ref:`introduction to working with forms <topics-forms-index>` + first. + +.. _ref-forms-api-bound-unbound: + +Bound and unbound forms +----------------------- + +A :class:`Form` instance is either **bound** to a set of data, or **unbound**. + + * If it's **bound** to a set of data, it's capable of validating that data + and rendering the form as HTML with the data displayed in the HTML. + + * If it's **unbound**, it cannot do validation (because there's no data to + validate!), but it can still render the blank form as HTML. + +To create an unbound :class:`Form` instance, simply instantiate the class:: + + >>> f = ContactForm() + +To bind data to a form, pass the data as a dictionary as the first parameter to +your :class:`Form` class constructor:: + + >>> data = {'subject': 'hello', + ... 'message': 'Hi there', + ... 'sender': 'foo@example.com', + ... 'cc_myself': True} + >>> f = ContactForm(data) + +In this dictionary, the keys are the field names, which correspond to the +attributes in your :class:`Form` class. The values are the data you're trying to +validate. These will usually be strings, but there's no requirement that they be +strings; the type of data you pass depends on the :class:`Field`, as we'll see +in a moment. + +.. attribute:: Form.is_bound + +If you need to distinguish between bound and unbound form instances at runtime, +check the value of the form's :attr:`~Form.is_bound` attribute:: + + >>> f = ContactForm() + >>> f.is_bound + False + >>> f = ContactForm({'subject': 'hello'}) + >>> f.is_bound + True + +Note that passing an empty dictionary creates a *bound* form with empty data:: + + >>> f = ContactForm({}) + >>> f.is_bound + True + +If you have a bound :class:`Form` instance and want to change the data somehow, +or if you want to bind an unbound :class:`Form` instance to some data, create +another :class:`Form` instance. There is no way to change data in a +:class:`Form` instance. Once a :class:`Form` instance has been created, you +should consider its data immutable, whether it has data or not. + +Using forms to validate data +---------------------------- + +.. method:: Form.is_valid() + +The primary task of a :class:`Form` object is to validate data. With a bound +:class:`Form` instance, call the :meth:`~Form.is_valid` method to run validation +and return a boolean designating whether the data was valid:: + + >>> data = {'subject': 'hello', + ... 'message': 'Hi there', + ... 'sender': 'foo@example.com', + ... 'cc_myself': True} + >>> f = ContactForm(data) + >>> f.is_valid() + True + +Let's try with some invalid data. In this case, ``subject`` is blank (an error, +because all fields are required by default) and ``sender`` is not a valid +e-mail address:: + + >>> data = {'subject': '', + ... 'message': 'Hi there', + ... 'sender': 'invalid e-mail address', + ... 'cc_myself': True} + >>> f = ContactForm(data) + >>> f.is_valid() + False + +.. attribute:: Form.errors + +Access the :attr:`~Form.errors` attribute to get a dictionary of error +messages:: + + >>> f.errors + {'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']} + +In this dictionary, the keys are the field names, and the values are lists of +Unicode strings representing the error messages. The error messages are stored +in lists because a field can have multiple error messages. + +You can access :attr:`~Form.errors` without having to call +:meth:`~Form.is_valid` first. The form's data will be validated the first time +either you call :meth:`~Form.is_valid` or access :attr:`~Form.errors`. + +The validation routines will only get called once, regardless of how many times +you access :attr:`~Form.errors` or call :meth:`~Form.is_valid`. This means that +if validation has side effects, those side effects will only be triggered once. + +Behavior of unbound forms +~~~~~~~~~~~~~~~~~~~~~~~~~ + +It's meaningless to validate a form with no data, but, for the record, here's +what happens with unbound forms:: + + >>> f = ContactForm() + >>> f.is_valid() + False + >>> f.errors + {} + +Accessing "clean" data +---------------------- + +Each ``Field`` in a ``Form`` class is responsible not only for validating data, +but also for "cleaning" it -- normalizing it to a consistent format. This is a +nice feature, because it allows data for a particular field to be input in +a variety of ways, always resulting in consistent output. + +For example, ``DateField`` normalizes input into a Python ``datetime.date`` +object. Regardless of whether you pass it a string in the format +``'1994-07-15'``, a ``datetime.date`` object or a number of other formats, +``DateField`` will always normalize it to a ``datetime.date`` object as long as +it's valid. + +Once you've created a ``Form`` instance with a set of data and validated it, +you can access the clean data via the ``cleaned_data`` attribute of the ``Form`` +object:: + + >>> data = {'subject': 'hello', + ... 'message': 'Hi there', + ... 'sender': 'foo@example.com', + ... 'cc_myself': True} + >>> f = ContactForm(data) + >>> f.is_valid() + True + >>> f.cleaned_data + {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} + +.. note:: + **New in Django development version** The ``cleaned_data`` attribute was + called ``clean_data`` in earlier releases. + +Note that any text-based field -- such as ``CharField`` or ``EmailField`` -- +always cleans the input into a Unicode string. We'll cover the encoding +implications later in this document. + +If your data does *not* validate, your ``Form`` instance will not have a +``cleaned_data`` attribute:: + + >>> data = {'subject': '', + ... 'message': 'Hi there', + ... 'sender': 'invalid e-mail address', + ... 'cc_myself': True} + >>> f = ContactForm(data) + >>> f.is_valid() + False + >>> f.cleaned_data + Traceback (most recent call last): + ... + AttributeError: 'ContactForm' object has no attribute 'cleaned_data' + +``cleaned_data`` will always *only* contain a key for fields defined in the +``Form``, even if you pass extra data when you define the ``Form``. In this +example, we pass a bunch of extra fields to the ``ContactForm`` constructor, +but ``cleaned_data`` contains only the form's fields:: + + >>> data = {'subject': 'hello', + ... 'message': 'Hi there', + ... 'sender': 'foo@example.com', + ... 'cc_myself': True, + ... 'extra_field_1': 'foo', + ... 'extra_field_2': 'bar', + ... 'extra_field_3': 'baz'} + >>> f = ContactForm(data) + >>> f.is_valid() + True + >>> f.cleaned_data # Doesn't contain extra_field_1, etc. + {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} + +``cleaned_data`` will include a key and value for *all* fields defined in the +``Form``, even if the data didn't include a value for fields that are not +required. In this example, the data dictionary doesn't include a value for the +``nick_name`` field, but ``cleaned_data`` includes it, with an empty value:: + + >>> class OptionalPersonForm(Form): + ... first_name = CharField() + ... last_name = CharField() + ... nick_name = CharField(required=False) + >>> data = {'first_name': u'John', 'last_name': u'Lennon'} + >>> f = OptionalPersonForm(data) + >>> f.is_valid() + True + >>> f.cleaned_data + {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} + +In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an +empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat +empty values as an empty string. Each field type knows what its "blank" value +is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. For +full details on each field's behavior in this case, see the "Empty value" note +for each field in the "Built-in ``Field`` classes" section below. + +You can write code to perform validation for particular form fields (based on +their name) or for the form as a whole (considering combinations of various +fields). More information about this is in :ref:`ref-forms-validation`. + +Outputting forms as HTML +------------------------ + +The second task of a ``Form`` object is to render itself as HTML. To do so, +simply ``print`` it:: + + >>> f = ContactForm() + >>> print f + <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr> + <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr> + <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr> + <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr> + +If the form is bound to data, the HTML output will include that data +appropriately. For example, if a field is represented by an +``<input type="text">``, the data will be in the ``value`` attribute. If a +field is represented by an ``<input type="checkbox">``, then that HTML will +include ``checked="checked"`` if appropriate:: + + >>> data = {'subject': 'hello', + ... 'message': 'Hi there', + ... 'sender': 'foo@example.com', + ... 'cc_myself': True} + >>> f = ContactForm(data) + >>> print f + <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" /></td></tr> + <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" /></td></tr> + <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" value="foo@example.com" /></td></tr> + <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked="checked" /></td></tr> + +This default output is a two-column HTML table, with a ``<tr>`` for each field. +Notice the following: + + * For flexibility, the output does *not* include the ``<table>`` and + ``</table>`` tags, nor does it include the ``<form>`` and ``</form>`` + tags or an ``<input type="submit">`` tag. It's your job to do that. + + * Each field type has a default HTML representation. ``CharField`` and + ``EmailField`` are represented by an ``<input type="text">``. + ``BooleanField`` is represented by an ``<input type="checkbox">``. Note + these are merely sensible defaults; you can specify which HTML to use for + a given field by using widgets, which we'll explain shortly. + + * The HTML ``name`` for each tag is taken directly from its attribute name + in the ``ContactForm`` class. + + * The text label for each field -- e.g. ``'Subject:'``, ``'Message:'`` and + ``'Cc myself:'`` is generated from the field name by converting all + underscores to spaces and upper-casing the first letter. Again, note + these are merely sensible defaults; you can also specify labels manually. + + * Each text label is surrounded in an HTML ``<label>`` tag, which points + to the appropriate form field via its ``id``. Its ``id``, in turn, is + generated by prepending ``'id_'`` to the field name. The ``id`` + attributes and ``<label>`` tags are included in the output by default, to + follow best practices, but you can change that behavior. + +Although ``<table>`` output is the default output style when you ``print`` a +form, other output styles are available. Each style is available as a method on +a form object, and each rendering method returns a Unicode object. + +``as_p()`` +~~~~~~~~~~ + +``Form.as_p()`` renders the form as a series of ``<p>`` tags, with each ``<p>`` +containing one field:: + + >>> f = ContactForm() + >>> f.as_p() + u'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>' + >>> print f.as_p() + <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p> + <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p> + <p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p> + <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p> + +``as_ul()`` +~~~~~~~~~~~ + +``Form.as_ul()`` renders the form as a series of ``<li>`` tags, with each +``<li>`` containing one field. It does *not* include the ``<ul>`` or ``</ul>``, +so that you can specify any HTML attributes on the ``<ul>`` for flexibility:: + + >>> f = ContactForm() + >>> f.as_ul() + u'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>' + >>> print f.as_ul() + <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li> + <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li> + <li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li> + <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li> + +``as_table()`` +~~~~~~~~~~~~~~ + +Finally, ``Form.as_table()`` outputs the form as an HTML ``<table>``. This is +exactly the same as ``print``. In fact, when you ``print`` a form object, it +calls its ``as_table()`` method behind the scenes:: + + >>> f = ContactForm() + >>> f.as_table() + u'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>' + >>> print f.as_table() + <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr> + <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr> + <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr> + <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr> + +.. _ref-forms-api-configuring-label: + +Configuring HTML ``<label>`` tags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An HTML ``<label>`` tag designates which label text is associated with which +form element. This small enhancement makes forms more usable and more accessible +to assistive devices. It's always a good idea to use ``<label>`` tags. + +By default, the form rendering methods include HTML ``id`` attributes on the +form elements and corresponding ``<label>`` tags around the labels. The ``id`` +attribute values are generated by prepending ``id_`` to the form field names. +This behavior is configurable, though, if you want to change the ``id`` +convention or remove HTML ``id`` attributes and ``<label>`` tags entirely. + +Use the ``auto_id`` argument to the ``Form`` constructor to control the label +and ``id`` behavior. This argument must be ``True``, ``False`` or a string. + +If ``auto_id`` is ``False``, then the form output will not include ``<label>`` +tags nor ``id`` attributes:: + + >>> f = ContactForm(auto_id=False) + >>> print f.as_table() + <tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /></td></tr> + <tr><th>Message:</th><td><input type="text" name="message" /></td></tr> + <tr><th>Sender:</th><td><input type="text" name="sender" /></td></tr> + <tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr> + >>> print f.as_ul() + <li>Subject: <input type="text" name="subject" maxlength="100" /></li> + <li>Message: <input type="text" name="message" /></li> + <li>Sender: <input type="text" name="sender" /></li> + <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> + >>> print f.as_p() + <p>Subject: <input type="text" name="subject" maxlength="100" /></p> + <p>Message: <input type="text" name="message" /></p> + <p>Sender: <input type="text" name="sender" /></p> + <p>Cc myself: <input type="checkbox" name="cc_myself" /></p> + +If ``auto_id`` is set to ``True``, then the form output *will* include +``<label>`` tags and will simply use the field name as its ``id`` for each form +field:: + + >>> f = ContactForm(auto_id=True) + >>> print f.as_table() + <tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" /></td></tr> + <tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" /></td></tr> + <tr><th><label for="sender">Sender:</label></th><td><input type="text" name="sender" id="sender" /></td></tr> + <tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself" /></td></tr> + >>> print f.as_ul() + <li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></li> + <li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li> + <li><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></li> + <li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></li> + >>> print f.as_p() + <p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></p> + <p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p> + <p><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></p> + <p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></p> + +If ``auto_id`` is set to a string containing the format character ``'%s'``, +then the form output will include ``<label>`` tags, and will generate ``id`` +attributes based on the format string. For example, for a format string +``'field_%s'``, a field named ``subject`` will get the ``id`` value +``'field_subject'``. Continuing our example:: + + >>> f = ContactForm(auto_id='id_for_%s') + >>> print f.as_table() + <tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" /></td></tr> + <tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" /></td></tr> + <tr><th><label for="id_for_sender">Sender:</label></th><td><input type="text" name="sender" id="id_for_sender" /></td></tr> + <tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></td></tr> + >>> print f.as_ul() + <li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li> + <li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></li> + <li><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></li> + <li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li> + >>> print f.as_p() + <p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></p> + <p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></p> + <p><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></p> + <p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></p> + +If ``auto_id`` is set to any other true value -- such as a string that doesn't +include ``%s`` -- then the library will act as if ``auto_id`` is ``True``. + +By default, ``auto_id`` is set to the string ``'id_%s'``. + +Normally, a colon (``:``) will be appended after any label name when a form is +rendered. It's possible to change the colon to another character, or omit it +entirely, using the ``label_suffix`` parameter:: + + >>> f = ContactForm(auto_id='id_for_%s', label_suffix='') + >>> print f.as_ul() + <li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li> + <li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" /></li> + <li><label for="id_for_sender">Sender</label> <input type="text" name="sender" id="id_for_sender" /></li> + <li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li> + >>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->') + >>> print f.as_ul() + <li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li> + <li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" /></li> + <li><label for="id_for_sender">Sender -></label> <input type="text" name="sender" id="id_for_sender" /></li> + <li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li> + +Note that the label suffix is added only if the last character of the +label isn't a punctuation character (``.``, ``!``, ``?`` or ``:``) + +Notes on field ordering +~~~~~~~~~~~~~~~~~~~~~~~ + +In the ``as_p()``, ``as_ul()`` and ``as_table()`` shortcuts, the fields are +displayed in the order in which you define them in your form class. For +example, in the ``ContactForm`` example, the fields are defined in the order +``subject``, ``message``, ``sender``, ``cc_myself``. To reorder the HTML +output, just change the order in which those fields are listed in the class. + +How errors are displayed +~~~~~~~~~~~~~~~~~~~~~~~~ + +If you render a bound ``Form`` object, the act of rendering will automatically +run the form's validation if it hasn't already happened, and the HTML output +will include the validation errors as a ``<ul class="errorlist">`` near the +field. The particular positioning of the error messages depends on the output +method you're using:: + + >>> data = {'subject': '', + ... 'message': 'Hi there', + ... 'sender': 'invalid e-mail address', + ... 'cc_myself': True} + >>> f = ContactForm(data, auto_id=False) + >>> print f.as_table() + <tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" /></td></tr> + <tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></td></tr> + <tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul><input type="text" name="sender" value="invalid e-mail address" /></td></tr> + <tr><th>Cc myself:</th><td><input checked="checked" type="checkbox" name="cc_myself" /></td></tr> + >>> print f.as_ul() + <li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" /></li> + <li>Message: <input type="text" name="message" value="Hi there" /></li> + <li><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul>Sender: <input type="text" name="sender" value="invalid e-mail address" /></li> + <li>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></li> + >>> print f.as_p() + <p><ul class="errorlist"><li>This field is required.</li></ul></p> + <p>Subject: <input type="text" name="subject" maxlength="100" /></p> + <p>Message: <input type="text" name="message" value="Hi there" /></p> + <p><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul></p> + <p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p> + <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p> + +Customizing the error list format +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, forms use ``django.forms.util.ErrorList`` to format validation +errors. If you'd like to use an alternate class for displaying errors, you can +pass that in at construction time:: + + >>> from django.forms.util import ErrorList + >>> class DivErrorList(ErrorList): + ... def __unicode__(self): + ... return self.as_divs() + ... def as_divs(self): + ... if not self: return u'' + ... return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self]) + >>> f = ContactForm(data, auto_id=False, error_class=DivErrorList) + >>> f.as_p() + <div class="errorlist"><div class="error">This field is required.</div></div> + <p>Subject: <input type="text" name="subject" maxlength="100" /></p> + <p>Message: <input type="text" name="message" value="Hi there" /></p> + <div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div> + <p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p> + <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p> + +More granular output +~~~~~~~~~~~~~~~~~~~~ + +The ``as_p()``, ``as_ul()`` and ``as_table()`` methods are simply shortcuts for +lazy developers -- they're not the only way a form object can be displayed. + +To display the HTML for a single field in your form, use dictionary lookup +syntax using the field's name as the key, and print the resulting object:: + + >>> f = ContactForm() + >>> print f['subject'] + <input id="id_subject" type="text" name="subject" maxlength="100" /> + >>> print f['message'] + <input type="text" name="message" id="id_message" /> + >>> print f['sender'] + <input type="text" name="sender" id="id_sender" /> + >>> print f['cc_myself'] + <input type="checkbox" name="cc_myself" id="id_cc_myself" /> + +Call ``str()`` or ``unicode()`` on the field to get its rendered HTML as a +string or Unicode object, respectively:: + + >>> str(f['subject']) + '<input id="id_subject" type="text" name="subject" maxlength="100" />' + >>> unicode(f['subject']) + u'<input id="id_subject" type="text" name="subject" maxlength="100" />' + +The field-specific output honors the form object's ``auto_id`` setting:: + + >>> f = ContactForm(auto_id=False) + >>> print f['message'] + <input type="text" name="message" /> + >>> f = ContactForm(auto_id='id_%s') + >>> print f['message'] + <input type="text" name="message" id="id_message" /> + +For a field's list of errors, access the field's ``errors`` attribute. This +is a list-like object that is displayed as an HTML ``<ul class="errorlist">`` +when printed:: + + >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} + >>> f = ContactForm(data, auto_id=False) + >>> print f['message'] + <input type="text" name="message" /> + >>> f['message'].errors + [u'This field is required.'] + >>> print f['message'].errors + <ul class="errorlist"><li>This field is required.</li></ul> + >>> f['subject'].errors + [] + >>> print f['subject'].errors + + >>> str(f['subject'].errors) + '' + +.. _binding-uploaded-files: + +Binding uploaded files to a form +-------------------------------- + +**New in Django development version** + +Dealing with forms that have ``FileField`` and ``ImageField`` fields +is a little more complicated than a normal form. + +Firstly, in order to upload files, you'll need to make sure that your +``<form>`` element correctly defines the ``enctype`` as +``"multipart/form-data"``:: + + <form enctype="multipart/form-data" method="post" action="/foo/"> + +Secondly, when you use the form, you need to bind the file data. File +data is handled separately to normal form data, so when your form +contains a ``FileField`` and ``ImageField``, you will need to specify +a second argument when you bind your form. So if we extend our +ContactForm to include an ``ImageField`` called ``mugshot``, we +need to bind the file data containing the mugshot image:: + + # Bound form with an image field + >>> from django.core.files.uploadedfile import SimpleUploadedFile + >>> data = {'subject': 'hello', + ... 'message': 'Hi there', + ... 'sender': 'foo@example.com', + ... 'cc_myself': True} + >>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)} + >>> f = ContactFormWithMugshot(data, file_data) + +In practice, you will usually specify ``request.FILES`` as the source +of file data (just like you use ``request.POST`` as the source of +form data):: + + # Bound form with an image field, data from the request + >>> f = ContactFormWithMugshot(request.POST, request.FILES) + +Constructing an unbound form is the same as always -- just omit both +form data *and* file data:: + + # Unbound form with a image field + >>> f = ContactFormWithMugshot() + +Testing for multipart forms +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're writing reusable views or templates, you may not know ahead of time +whether your form is a multipart form or not. The ``is_multipart()`` method +tells you whether the form requires multipart encoding for submission:: + + >>> f = ContactFormWithMugshot() + >>> f.is_multipart() + True + +Here's an example of how you might use this in a template:: + + {% if form.is_multipart %} + <form enctype="multipart/form-data" method="post" action="/foo/"> + {% else %} + <form method="post" action="/foo/"> + {% endif %} + {{ form }} + </form> + +Subclassing forms +----------------- + +If you have multiple ``Form`` classes that share fields, you can use +subclassing to remove redundancy. + +When you subclass a custom ``Form`` class, the resulting subclass will +include all fields of the parent class(es), followed by the fields you define +in the subclass. + +In this example, ``ContactFormWithPriority`` contains all the fields from +``ContactForm``, plus an additional field, ``priority``. The ``ContactForm`` +fields are ordered first:: + + >>> class ContactFormWithPriority(ContactForm): + ... priority = forms.CharField() + >>> f = ContactFormWithPriority(auto_id=False) + >>> print f.as_ul() + <li>Subject: <input type="text" name="subject" maxlength="100" /></li> + <li>Message: <input type="text" name="message" /></li> + <li>Sender: <input type="text" name="sender" /></li> + <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> + <li>Priority: <input type="text" name="priority" /></li> + +It's possible to subclass multiple forms, treating forms as "mix-ins." In this +example, ``BeatleForm`` subclasses both ``PersonForm`` and ``InstrumentForm`` +(in that order), and its field list includes the fields from the parent +classes:: + + >>> class PersonForm(Form): + ... first_name = CharField() + ... last_name = CharField() + >>> class InstrumentForm(Form): + ... instrument = CharField() + >>> class BeatleForm(PersonForm, InstrumentForm): + ... haircut_type = CharField() + >>> b = BeatleForm(auto_id=False) + >>> print b.as_ul() + <li>First name: <input type="text" name="first_name" /></li> + <li>Last name: <input type="text" name="last_name" /></li> + <li>Instrument: <input type="text" name="instrument" /></li> + <li>Haircut type: <input type="text" name="haircut_type" /></li> + +.. _form-prefix: + +Prefixes for forms +------------------ + +.. attribute:: Form.prefix + +You can put several Django forms inside one ``<form>`` tag. To give each +``Form`` its own namespace, use the ``prefix`` keyword argument:: + + >>> mother = PersonForm(prefix="mother") + >>> father = PersonForm(prefix="father") + >>> print mother.as_ul() + <li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" /></li> + <li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" /></li> + >>> print father.as_ul() + <li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li> + <li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li> diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt new file mode 100644 index 0000000000..161c550d37 --- /dev/null +++ b/docs/ref/forms/fields.txt @@ -0,0 +1,751 @@ +.. _ref-forms-fields: + +=========== +Form fields +=========== + +.. module:: django.forms.fields + :synopsis: Django's built-in form fields. + +.. currentmodule:: django.forms + +.. class:: Field(**kwargs) + +When you create a ``Form`` class, the most important part is defining the +fields of the form. Each field has custom validation logic, along with a few +other hooks. + +.. method:: Field.clean(value) + +Although the primary way you'll use ``Field`` classes is in ``Form`` classes, +you can also instantiate them and use them directly to get a better idea of +how they work. Each ``Field`` instance has a ``clean()`` method, which takes +a single argument and either raises a ``django.forms.ValidationError`` +exception or returns the clean value:: + + >>> f = forms.EmailField() + >>> f.clean('foo@example.com') + u'foo@example.com' + >>> f.clean(u'foo@example.com') + u'foo@example.com' + >>> f.clean('invalid e-mail address') + Traceback (most recent call last): + ... + ValidationError: [u'Enter a valid e-mail address.'] + +If you've used Django's old forms/validation framework, take care in noticing +this ``ValidationError`` is different than the previous ``ValidationError``. +This one lives at ``django.forms.ValidationError`` rather than +``django.core.validators.ValidationError``. + +Core field arguments +-------------------- + +Each ``Field`` class constructor takes at least these arguments. Some +``Field`` classes take additional, field-specific arguments, but the following +should *always* be accepted: + +``required`` +~~~~~~~~~~~~ + +.. attribute:: Field.required + +By default, each ``Field`` class assumes the value is required, so if you pass +an empty value -- either ``None`` or the empty string (``""``) -- then +``clean()`` will raise a ``ValidationError`` exception:: + + >>> f = forms.CharField() + >>> f.clean('foo') + u'foo' + >>> 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(' ') + u' ' + >>> f.clean(0) + u'0' + >>> f.clean(True) + u'True' + >>> f.clean(False) + u'False' + +To specify that a field is *not* required, pass ``required=False`` to the +``Field`` constructor:: + + >>> f = forms.CharField(required=False) + >>> f.clean('foo') + u'foo' + >>> f.clean('') + u'' + >>> f.clean(None) + u'' + >>> f.clean(0) + u'0' + >>> f.clean(True) + u'True' + >>> f.clean(False) + u'False' + +If a ``Field`` has ``required=False`` and you pass ``clean()`` an empty value, +then ``clean()`` will return a *normalized* empty value rather than raising +``ValidationError``. For ``CharField``, this will be a Unicode empty string. +For other ``Field`` classes, it might be ``None``. (This varies from field to +field.) + +``label`` +~~~~~~~~~ + +.. attribute:: Field.label + +The ``label`` argument lets you specify the "human-friendly" label for this +field. This is used when the ``Field`` is displayed in a ``Form``. + +As explained in "Outputting forms as HTML" above, the default label for a +``Field`` is generated from the field name by converting all underscores to +spaces and upper-casing the first letter. Specify ``label`` if that default +behavior doesn't result in an adequate label. + +Here's a full example ``Form`` that implements ``label`` for two of its fields. +We've specified ``auto_id=False`` to simplify the output:: + + >>> class CommentForm(forms.Form): + ... name = forms.CharField(label='Your name') + ... url = forms.URLField(label='Your Web site', required=False) + ... comment = forms.CharField() + >>> f = CommentForm(auto_id=False) + >>> print f + <tr><th>Your name:</th><td><input type="text" name="name" /></td></tr> + <tr><th>Your Web site:</th><td><input type="text" name="url" /></td></tr> + <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> + +``initial`` +~~~~~~~~~~~ + +.. attribute:: Field.initial + +The ``initial`` argument lets you specify the initial value to use when +rendering this ``Field`` in an unbound ``Form``. + +The use-case for this is when you want to display an "empty" form in which a +field is initialized to a particular value. For example:: + + >>> class CommentForm(forms.Form): + ... name = forms.CharField(initial='Your name') + ... url = forms.URLField(initial='http://') + ... comment = forms.CharField() + >>> f = CommentForm(auto_id=False) + >>> print f + <tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr> + <tr><th>Url:</th><td><input type="text" name="url" value="http://" /></td></tr> + <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> + +You may be thinking, why not just pass a dictionary of the initial values as +data when displaying the form? Well, if you do that, you'll trigger validation, +and the HTML output will include any validation errors:: + + >>> class CommentForm(forms.Form): + ... name = forms.CharField() + ... url = forms.URLField() + ... comment = forms.CharField() + >>> default_data = {'name': 'Your name', 'url': 'http://'} + >>> f = CommentForm(default_data, auto_id=False) + >>> print f + <tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr> + <tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="text" name="url" value="http://" /></td></tr> + <tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" /></td></tr> + +This is why ``initial`` values are only displayed for unbound forms. For bound +forms, the HTML output will use the bound data. + +Also note that ``initial`` values are *not* used as "fallback" data in +validation if a particular field's value is not given. ``initial`` values are +*only* intended for initial form display:: + + >>> class CommentForm(forms.Form): + ... name = forms.CharField(initial='Your name') + ... url = forms.URLField(initial='http://') + ... comment = forms.CharField() + >>> data = {'name': '', 'url': '', 'comment': 'Foo'} + >>> f = CommentForm(data) + >>> f.is_valid() + False + # The form does *not* fall back to using the initial values. + >>> f.errors + {'url': [u'This field is required.'], 'name': [u'This field is required.']} + +``widget`` +~~~~~~~~~~ + +.. attribute:: Field.widget + +The ``widget`` argument lets you specify a ``Widget`` class to use when +rendering this ``Field``. See :ref:`ref-forms-widgets` for more information. + +``help_text`` +~~~~~~~~~~~~~ + +.. attribute:: Field.help_text + +The ``help_text`` argument lets you specify descriptive text for this +``Field``. If you provide ``help_text``, it will be displayed next to the +``Field`` when the ``Field`` is rendered by one of the convenience ``Form`` +methods (e.g., ``as_ul()``). + +Here's a full example ``Form`` that implements ``help_text`` for two of its +fields. We've specified ``auto_id=False`` to simplify the output:: + + >>> class HelpTextContactForm(forms.Form): + ... subject = forms.CharField(max_length=100, help_text='100 characters max.') + ... message = forms.CharField() + ... sender = forms.EmailField(help_text='A valid e-mail address, please.') + ... cc_myself = forms.BooleanField(required=False) + >>> f = HelpTextContactForm(auto_id=False) + >>> print f.as_table() + <tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /><br />100 characters max.</td></tr> + <tr><th>Message:</th><td><input type="text" name="message" /></td></tr> + <tr><th>Sender:</th><td><input type="text" name="sender" /><br />A valid e-mail address, please.</td></tr> + <tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr> + >>> print f.as_ul() + <li>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</li> + <li>Message: <input type="text" name="message" /></li> + <li>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</li> + <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> + >>> print f.as_p() + <p>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</p> + <p>Message: <input type="text" name="message" /></p> + <p>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</p> + <p>Cc myself: <input type="checkbox" name="cc_myself" /></p> + +``error_messages`` +~~~~~~~~~~~~~~~~~~ + +.. attribute:: Field.error_messages + +**New in Django development version** + +The ``error_messages`` argument lets you override the default messages that the +field will raise. Pass in a dictionary with keys matching the error messages you +want to override. For example, here is the default error message:: + + >>> generic = forms.CharField() + >>> generic.clean('') + Traceback (most recent call last): + ... + ValidationError: [u'This field is required.'] + +And here is a custom error message:: + + >>> name = forms.CharField(error_messages={'required': 'Please enter your name'}) + >>> name.clean('') + Traceback (most recent call last): + ... + ValidationError: [u'Please enter your name'] + +In the `built-in Field classes`_ section below, each ``Field`` defines the +error message keys it uses. + +Dynamic initial values +---------------------- + +The ``initial`` argument to ``Field`` (explained above) lets you hard-code the +initial value for a ``Field`` -- but what if you want to declare the initial +value at runtime? For example, you might want to fill in a ``username`` field +with the username of the current session. + +To accomplish this, use the ``initial`` argument to a ``Form``. This argument, +if given, should be a dictionary mapping field names to initial values. Only +include the fields for which you're specifying an initial value; it's not +necessary to include every field in your form. For example:: + + >>> class CommentForm(forms.Form): + ... name = forms.CharField() + ... url = forms.URLField() + ... comment = forms.CharField() + >>> f = CommentForm(initial={'name': 'your username'}, auto_id=False) + >>> print f + <tr><th>Name:</th><td><input type="text" name="name" value="your username" /></td></tr> + <tr><th>Url:</th><td><input type="text" name="url" /></td></tr> + <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> + >>> f = CommentForm(initial={'name': 'another username'}, auto_id=False) + >>> print f + <tr><th>Name:</th><td><input type="text" name="name" value="another username" /></td></tr> + <tr><th>Url:</th><td><input type="text" name="url" /></td></tr> + <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> + +Just like the ``initial`` parameter to ``Field``, these values are only +displayed for unbound forms, and they're not used as fallback values if a +particular value isn't provided. + +Finally, note that if a ``Field`` defines ``initial`` *and* you include +``initial`` when instantiating the ``Form``, then the latter ``initial`` will +have precedence. In this example, ``initial`` is provided both at the field +level and at the form instance level, and the latter gets precedence:: + + >>> class CommentForm(forms.Form): + ... name = forms.CharField(initial='class') + ... url = forms.URLField() + ... comment = forms.CharField() + >>> f = CommentForm(initial={'name': 'instance'}, auto_id=False) + >>> print f + <tr><th>Name:</th><td><input type="text" name="name" value="instance" /></td></tr> + <tr><th>Url:</th><td><input type="text" name="url" /></td></tr> + <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> + + +Built-in ``Field`` classes +-------------------------- + +Naturally, the ``forms`` library comes with a set of ``Field`` classes that +represent common validation needs. This section documents each built-in field. + +For each field, we describe the default widget used if you don't specify +``widget``. We also specify the value returned when you provide an empty value +(see the section on ``required`` above to understand what that means). + +``BooleanField`` +~~~~~~~~~~~~~~~~ + +.. class:: BooleanField(**kwargs) + + * Default widget: ``CheckboxInput`` + * Empty value: ``False`` + * Normalizes to: A Python ``True`` or ``False`` value. + * Validates that the check box is checked (i.e. the value is ``True``) if + the field has ``required=True``. + * Error message keys: ``required`` + +**New in Django development version:** The empty value for a ``CheckboxInput`` +(and hence the standard ``BooleanField``) has changed to return ``False`` +instead of ``None`` in the development version. + +.. note:: + Since all ``Field`` subclasses have ``required=True`` by default, the + validation condition here is important. If you want to include a checkbox + in your form that can be either checked or unchecked, you must remember to + pass in ``required=False`` when creating the ``BooleanField``. + +``CharField`` +~~~~~~~~~~~~~ + +.. class:: CharField(**kwargs) + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates ``max_length`` or ``min_length``, if they are provided. + Otherwise, all inputs are valid. + * Error message keys: ``required``, ``max_length``, ``min_length`` + +Has two optional arguments for validation: + +.. attribute:: CharField.max_length +.. attribute:: CharField.min_length + If provided, these arguments ensure that the string is at most or at least + the given length. + +``ChoiceField`` +~~~~~~~~~~~~~~~ + +.. class:: ChoiceField(**kwargs) + + * Default widget: ``Select`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value exists in the list of choices. + * Error message keys: ``required``, ``invalid_choice`` + +Takes one extra required argument: + +.. attribute:: ChoiceField.choices + An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this + field. + +``DateField`` +~~~~~~~~~~~~~ + +.. class:: DateField(**kwargs) + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.date`` object. + * Validates that the given value is either a ``datetime.date``, + ``datetime.datetime`` or string formatted in a particular date format. + * Error message keys: ``required``, ``invalid`` + +Takes one optional argument: + +.. attribute:: DateField.input_formats + A list of formats used to attempt to convert a string to a valid + ``datetime.date`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' + '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006' + '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006' + '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006' + '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006' + +``DateTimeField`` +~~~~~~~~~~~~~~~~~ + +.. class:: DateTimeField(**kwargs) + + * Default widget: ``DateTimeInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.datetime`` object. + * Validates that the given value is either a ``datetime.datetime``, + ``datetime.date`` or string formatted in a particular datetime format. + * Error message keys: ``required``, ``invalid`` + +Takes one optional argument: + +.. attribute:: DateTimeField.input_formats + A list of formats used to attempt to convert a string to a valid + ``datetime.datetime`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' + '%Y-%m-%d %H:%M', # '2006-10-25 14:30' + '%Y-%m-%d', # '2006-10-25' + '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59' + '%m/%d/%Y %H:%M', # '10/25/2006 14:30' + '%m/%d/%Y', # '10/25/2006' + '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59' + '%m/%d/%y %H:%M', # '10/25/06 14:30' + '%m/%d/%y', # '10/25/06' + +**New in Django development version:** The ``DateTimeField`` used to use a +``TextInput`` widget by default. This has now changed. + +``DecimalField`` +~~~~~~~~~~~~~~~~ + +.. class:: DecimalField(**kwargs) + +**New in Django development version** + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``decimal``. + * Validates that the given value is a decimal. Leading and trailing + whitespace is ignored. + * Error message keys: ``required``, ``invalid``, ``max_value``, + ``min_value``, ``max_digits``, ``max_decimal_places``, + ``max_whole_digits`` + +Takes four optional arguments: + +.. attribute:: DecimalField.max_value +.. attribute:: DecimalField.min_value + These attributes define the limits for the fields value. + +.. attribute:: DecimalField.max_digits + The maximum number of digits (those before the decimal point plus those + after the decimal point, with leading zeros stripped) permitted in the + value. + +.. attribute:: DecimalField.decimal_places + The maximum number of decimal places permitted. + +``EmailField`` +~~~~~~~~~~~~~~ + +.. class:: EmailField(**kwargs) + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value is a valid e-mail address, using a + moderately complex regular expression. + * Error message keys: ``required``, ``invalid`` + +Has two optional arguments for validation, ``max_length`` and ``min_length``. +If provided, these arguments ensure that the string is at most or at least the +given length. + +``FileField`` +~~~~~~~~~~~~~ + +.. class:: FileField(**kwargs) + +**New in Django development version** + + * Default widget: ``FileInput`` + * Empty value: ``None`` + * Normalizes to: An ``UploadedFile`` object that wraps the file content + and file name into a single object. + * Validates that non-empty file data has been bound to the form. + * Error message keys: ``required``, ``invalid``, ``missing``, ``empty`` + +To learn more about the ``UploadedFile`` object, see the :ref:`file uploads +documentation <topics-file-uploads>`. + +When you use a ``FileField`` in a form, you must also remember to +:ref:`bind the file data to the form <topics-file-uploads>`. + +``FilePathField`` +~~~~~~~~~~~~~~~~~ + +.. class:: FilePathField(**kwargs) + +**New in Django development version** + + * Default widget: ``Select`` + * Empty value: ``None`` + * Normalizes to: A unicode object + * Validates that the selected choice exists in the list of choices. + * Error message keys: ``required``, ``invalid_choice`` + +The field allows choosing from files inside a certain directory. It takes three +extra arguments; only ``path`` is required: + +.. attribute:: FilePathField.path + The absolute path to the directory whose contents you want listed. This + directory must exist. + +.. attribute:: FilePathField.recursive + If ``False`` (the default) only the direct contents of ``path`` will be + offered as choices. If ``True``, the directory will be descended into + recursively and all descendants will be listed as choices. + +.. attribute:: FilePathField.match + A regular expression pattern; only files with names matching this expression + will be allowed as choices. + +``FloatField`` +~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python float. + * Validates that the given value is an float. Leading and trailing + whitespace is allowed, as in Python's ``float()`` function. + * Error message keys: ``required``, ``invalid``, ``max_value``, + ``min_value`` + +Takes two optional arguments for validation, ``max_value`` and ``min_value``. +These control the range of values permitted in the field. + +``ImageField`` +~~~~~~~~~~~~~~ + +.. class:: ImageField(**kwargs) + +**New in Django development version** + + * Default widget: ``FileInput`` + * Empty value: ``None`` + * Normalizes to: An ``UploadedFile`` object that wraps the file content + and file name into a single object. + * Validates that file data has been bound to the form, and that the + file is of an image format understood by PIL. + * Error message keys: ``required``, ``invalid``, ``missing``, ``empty``, + ``invalid_image`` + +Using an ImageField requires that the `Python Imaging Library`_ is installed. + +When you use an ``ImageField`` on a form, you must also remember to +:ref:`bind the file data to the form <topics-file-uploads>`. + +.. _Python Imaging Library: http://www.pythonware.com/products/pil/ + +``IntegerField`` +~~~~~~~~~~~~~~~~ + +.. class:: IntegerField(**kwargs) + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python integer or long integer. + * Validates that the given value is an integer. Leading and trailing + whitespace is allowed, as in Python's ``int()`` function. + * Error message keys: ``required``, ``invalid``, ``max_value``, + ``min_value`` + +Takes two optional arguments for validation: + +.. attribute:: IntegerField.max_value +.. attribute:: IntegerField.min_value + These control the range of values permitted in the field. + +``IPAddressField`` +~~~~~~~~~~~~~~~~~~ + +.. class:: IPAddressField(**kwargs) + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value is a valid IPv4 address, using a regular + expression. + * Error message keys: ``required``, ``invalid`` + +``MultipleChoiceField`` +~~~~~~~~~~~~~~~~~~~~~~~ + +.. class:: MultipleChoiceField(**kwargs) + + * Default widget: ``SelectMultiple`` + * Empty value: ``[]`` (an empty list) + * Normalizes to: A list of Unicode objects. + * Validates that every value in the given list of values exists in the list + of choices. + * Error message keys: ``required``, ``invalid_choice``, ``invalid_list`` + +Takes one extra argument, ``choices``, as for ``ChoiceField``. + +``NullBooleanField`` +~~~~~~~~~~~~~~~~~~~~ + +.. class:: NullBooleanField(**kwargs) + + * Default widget: ``NullBooleanSelect`` + * Empty value: ``None`` + * Normalizes to: A Python ``True``, ``False`` or ``None`` value. + * Validates nothing (i.e., it never raises a ``ValidationError``). + +``RegexField`` +~~~~~~~~~~~~~~ + +.. class:: RegexField(**kwargs) + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value matches against a certain regular + expression. + * Error message keys: ``required``, ``invalid`` + +Takes one required argument: + +.. attribute:: RegexField.regex`` + A regular expression specified either as a string or a compiled regular + expression object. + +Also takes ``max_length`` and ``min_length``, which work just as they do for +``CharField``. + +The optional argument ``error_message`` is also accepted for backwards +compatibility. The preferred way to provide an error message is to use the +``error_messages`` argument, passing a dictionary with ``'invalid'`` as a key +and the error message as the value. + +``TimeField`` +~~~~~~~~~~~~~ + +.. class:: TimeField(**kwargs) + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python ``datetime.time`` object. + * Validates that the given value is either a ``datetime.time`` or string + formatted in a particular time format. + * Error message keys: ``required``, ``invalid`` + +Takes one optional argument: + +.. attribute:: TimeField.input_formats + A list of formats used to attempt to convert a string to a valid + ``datetime.time`` object. + +If no ``input_formats`` argument is provided, the default input formats are:: + + '%H:%M:%S', # '14:30:59' + '%H:%M', # '14:30' + +``URLField`` +~~~~~~~~~~~~ + +.. class:: URLField(**kwargs) + + * Default widget: ``TextInput`` + * Empty value: ``''`` (an empty string) + * Normalizes to: A Unicode object. + * Validates that the given value is a valid URL. + * Error message keys: ``required``, ``invalid``, ``invalid_link`` + +Takes the following optional arguments: + + +.. attribute:: URLField.max_length +.. attribute:: URLField.min_length + Same as ``CharField.max_length`` and ``CharField.min_length``. + +.. attribute:: URLField.verify_exists + If ``True``, the validator will attempt to load the given URL, raising + ``ValidationError`` if the page gives a 404. Defaults to ``False``. + +.. attribute:: URLField.validator_user_agent + String used as the user-agent used when checking for a URL's existence. + Defaults to the value of the ``URL_VALIDATOR_USER_AGENT`` setting. + +Slightly complex built-in ``Field`` classes +------------------------------------------- + +The following are not yet documented. + +.. class:: ComboField(**kwargs) + +.. class:: MultiValueField(**kwargs) + +.. class:: SplitDateTimeField(**kwargs) + +Fields which handle relationships +--------------------------------- + +For representing relationships between models, two fields are +provided which can derive their choices from a ``QuerySet``: + +.. class:: ModelChoiceField(**kwargs) +.. class:: ModelMultipleChoiceField(**kwargs) + +These fields place one or more model objects into the ``cleaned_data`` +dictionary of forms in which they're used. Both of these fields have an +additional required argument: + +.. attribute:: ModelChoiceField.queryset + A ``QuerySet`` of model objects from which the choices for the + field will be derived, and which will be used to validate the + user's selection. + +``ModelChoiceField`` +~~~~~~~~~~~~~~~~~~~~ + +Allows the selection of a single model object, suitable for +representing a foreign key. + +The ``__unicode__`` method of the model will be called to generate +string representations of the objects for use in the field's choices; +to provide customized representations, subclass ``ModelChoiceField`` +and override ``label_from_instance``. This method will receive a model +object, and should return a string suitable for representing it. For +example:: + + class MyModelChoiceField(ModelChoiceField): + def label_from_instance(self, obj): + return "My Object #%i" % obj.id + +``ModelMultipleChoiceField`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Allows the selection of one or more model objects, suitable for +representing a many-to-many relation. As with ``ModelChoiceField``, +you can use ``label_from_instance`` to customize the object +representations. + +Creating custom fields +---------------------- + +If the built-in ``Field`` classes don't meet your needs, you can easily create +custom ``Field`` classes. To do this, just create a subclass of +``django.forms.Field``. Its only requirements are that it implement a +``clean()`` method and that its ``__init__()`` method accept the core arguments +mentioned above (``required``, ``label``, ``initial``, ``widget``, +``help_text``). diff --git a/docs/ref/forms/index.txt b/docs/ref/forms/index.txt new file mode 100644 index 0000000000..a9e041c2a7 --- /dev/null +++ b/docs/ref/forms/index.txt @@ -0,0 +1,14 @@ +.. _ref-forms-index: + +Forms +===== + +Detailed form API reference. For introductory material, see :ref:`topics-forms-index`. + +.. toctree:: + :maxdepth: 1 + + api + fields + widgets + validation
\ No newline at end of file diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt new file mode 100644 index 0000000000..56c0e098c3 --- /dev/null +++ b/docs/ref/forms/validation.txt @@ -0,0 +1,109 @@ +.. _ref-forms-validation: + +F and field validation +====================== + +Form validation happens when the data is cleaned. If you want to customize +this process, there are various places you can change, each one serving a +different purpose. Three types of cleaning methods are run during form +processing. These are normally executed when you call the ``is_valid()`` +method on a form. There are other things that can trigger cleaning and +validation (accessing the ``errors`` attribute or calling ``full_clean()`` +directly), but normally they won't be needed. + +In general, any cleaning method can raise ``ValidationError`` if there is a +problem with the data it is processing, passing the relevant error message to +the ``ValidationError`` constructor. If no ``ValidationError`` is raised, the +method should return the cleaned (normalized) data as a Python object. + +If you detect multiple errors during a cleaning method and wish to signal all +of them to the form submitter, it is possible to pass a list of errors to the +``ValidationError`` constructor. + +The three types of cleaning methods are: + + * The ``clean()`` method on a Field subclass. This is responsible + for cleaning the data in a way that is generic for that type of field. + For example, a FloatField will turn the data into a Python ``float`` or + raise a ``ValidationError``. + + * The ``clean_<fieldname>()`` method in a form subclass -- where + ``<fieldname>`` is replaced with the name of the form field attribute. + This method does any cleaning that is specific to that particular + attribute, unrelated to the type of field that it is. This method is not + passed any parameters. You will need to look up the value of the field + in ``self.cleaned_data`` and remember that it will be a Python object + at this point, not the original string submitted in the form (it will be + in ``cleaned_data`` because the general field ``clean()`` method, above, + has already cleaned the data once). + + For example, if you wanted to validate that the contents of a + ``CharField`` called ``serialnumber`` was unique, + ``clean_serialnumber()`` would be the right place to do this. You don't + need a specific field (it's just a ``CharField``), but you want a + formfield-specific piece of validation and, possibly, + cleaning/normalizing the data. + + * The Form subclass's ``clean()`` method. This method can perform + any validation that requires access to multiple fields from the form at + once. This is where you might put in things to check that if field ``A`` + is supplied, field ``B`` must contain a valid e-mail address and the + like. The data that this method returns is the final ``cleaned_data`` + attribute for the form, so don't forget to return the full list of + cleaned data if you override this method (by default, ``Form.clean()`` + just returns ``self.cleaned_data``). + + Note that any errors raised by your ``Form.clean()`` override will not + be associated with any field in particular. They go into a special + "field" (called ``__all__``), which you can access via the + ``non_field_errors()`` method if you need to. + +These methods are run in the order given above, one field at a time. That is, +for each field in the form (in the order they are declared in the form +definition), the ``Field.clean()`` method (or its override) is run, then +``clean_<fieldname>()``. Finally, once those two methods are run for every +field, the ``Form.clean()`` method, or its override, is executed. + +As mentioned above, any of these methods can raise a ``ValidationError``. For +any field, if the ``Field.clean()`` method raises a ``ValidationError``, any +field-specific cleaning method is not called. However, the cleaning methods +for all remaining fields are still executed. + +The ``clean()`` method for the ``Form`` class or subclass is always run. If +that method raises a ``ValidationError``, ``cleaned_data`` will be an empty +dictionary. + +The previous paragraph means that if you are overriding ``Form.clean()``, you +should iterate through ``self.cleaned_data.items()``, possibly considering the +``_errors`` dictionary attribute on the form as well. In this way, you will +already know which fields have passed their individual validation requirements. + +A simple example +~~~~~~~~~~~~~~~~ + +Here's a simple example of a custom field that validates its input is a string +containing comma-separated e-mail addresses, with at least one address. We'll +keep it simple and assume e-mail validation is contained in a function called +``is_valid_email()``. The full class:: + + from django import forms + + class MultiEmailField(forms.Field): + def clean(self, value): + if not value: + raise forms.ValidationError('Enter at least one e-mail address.') + emails = value.split(',') + for email in emails: + if not is_valid_email(email): + raise forms.ValidationError('%s is not a valid e-mail address.' % email) + return emails + +Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use +this in a form. Simply use ``MultiEmailField`` instead of ``forms.EmailField``, +like so:: + + class ContactForm(forms.Form): + subject = forms.CharField(max_length=100) + message = forms.CharField() + senders = MultiEmailField() + cc_myself = forms.BooleanField(required=False) diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt new file mode 100644 index 0000000000..184515ec95 --- /dev/null +++ b/docs/ref/forms/widgets.txt @@ -0,0 +1,156 @@ +.. _ref-forms-widgets: + +======= +Widgets +======= + +.. module:: django.forms.widgets + :synopsis: Django's built-in form widgets. + +.. currentmodule:: django.forms + +A widget is Django's representation of a HTML input element. The widget +handles the rendering of the HTML, and the extraction of data from a GET/POST +dictionary that corresponds to the widget. + +Django provides a representation of all the basic HTML widgets, plus some +commonly used groups of widgets: + +.. class:: TextInput + Text input: ``<input type='text' ...>`` + +.. class:: PasswordInput + Password input: ``<input type='password' ...>`` + +.. class:: HiddenInput + Hidden input: ``<input type='hidden' ...>`` + +.. class:: MultipleHiddenInput + Multiple ``<input type='hidden' ...>`` widgets. + +.. class:: FileInput + File upload input: ``<input type='file' ...>`` + +.. class:: DateTimeInput + Date/time input as a simple text box: ``<input type='text' ...>`` + + **New in Django development version:** + +.. class:: Textarea + Text area: ``<textarea>...</textarea>`` + +.. class:: CheckboxInput + Checkbox: ``<input type='checkbox' ...>`` + +.. class:: Select + Select widget: ``<select><option ...>...</select>`` + +.. class:: NullBooleanSelect + Select widget with options 'Unknown', 'Yes' and 'No' + +.. class:: SelectMultiple + Select widget allowing multiple selection: ``<select + multiple='multiple'>...</select>`` + +.. class:: RadioSelect + A list of radio buttons: + + .. code-block:: html + + <ul> + <li><input type='radio' ...></li> + ... + </ul> + +.. class:: CheckboxSelectMultiple + A list of checkboxes: + + .. code-block:: html + + <ul> + <li><input type='checkbox' ...></li> + ... + </ul> + +.. class:: MultiWidget + Wrapper around multiple other widgets + +.. class:: SplitDateTimeWidget + Wrapper around two ``TextInput`` widgets: one for the date, and one for the + time. + +Specifying widgets +------------------ + +.. attribute:: Form.widget + +Whenever you specify a field on a form, Django will use a default widget +that is appropriate to the type of data that is to be displayed. To find +which widget is used on which field, see the documentation for the +built-in Field classes. + +However, if you want to use a different widget for a field, you can - +just use the 'widget' argument on the field definition. For example:: + + class CommentForm(forms.Form): + name = forms.CharField() + url = forms.URLField() + comment = forms.CharField(widget=forms.Textarea) + +This would specify a form with a comment that uses a larger Textarea widget, +rather than the default TextInput widget. + +Customizing widget instances +---------------------------- + +When Django renders a widget as HTML, it only renders the bare minimum +HTML - Django doesn't add a class definition, or any other widget-specific +attributes. This means that all 'TextInput' widgets will appear the same +on your web page. + +If you want to make one widget look different to another, you need to +specify additional attributes for each widget. When you specify a +widget, you can provide a list of attributes that will be added to the +rendered HTML for the widget. + +For example, take the following simple form:: + + class CommentForm(forms.Form): + name = forms.CharField() + url = forms.URLField() + comment = forms.CharField() + +This form will include three default TextInput widgets, with default rendering - +no CSS class, no extra attributes. This means that the input boxes provided for +each widget will be rendered exactly the same:: + + >>> f = CommentForm(auto_id=False) + >>> f.as_table() + <tr><th>Name:</th><td><input type="text" name="name" /></td></tr> + <tr><th>Url:</th><td><input type="text" name="url"/></td></tr> + <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> + + +On a real web page, you probably don't want every widget to look the same. You +might want a larger input element for the comment, and you might want the 'name' +widget to have some special CSS class. To do this, you use the ``attrs`` +argument when creating the widget: + +.. attribute:: Widget.attrs + +For example:: + + class CommentForm(forms.Form): + name = forms.CharField( + widget=forms.TextInput(attrs={'class':'special'})) + url = forms.URLField() + comment = forms.CharField( + widget=forms.TextInput(attrs={'size':'40'})) + +Django will then include the extra attributes in the rendered output:: + + >>> f = CommentForm(auto_id=False) + >>> f.as_table() + <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr> + <tr><th>Url:</th><td><input type="text" name="url"/></td></tr> + <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr> |
