diff -r 5ff1fc726848 -r c6bca38c1cbf parts/django/docs/topics/forms/index.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parts/django/docs/topics/forms/index.txt Sat Jan 08 11:20:57 2011 +0530 @@ -0,0 +1,402 @@ +================== +Working with forms +================== + +.. admonition:: About this document + + This document provides an introduction to Django's form handling features. + For a more detailed look at specific areas of the forms API, see + :doc:`/ref/forms/api`, :doc:`/ref/forms/fields`, and + :doc:`/ref/forms/validation`. + +.. highlightlang:: html+django + +``django.forms`` is Django's form-handling library. + +While it is possible to process form submissions just using Django's +:class:`~django.http.HttpRequest` class, using the form library takes care of a +number of common form-related tasks. Using it, you can: + + 1. Display an HTML form with automatically generated form widgets. + 2. Check submitted data against a set of validation rules. + 3. Redisplay a form in the case of validation errors. + 4. Convert submitted form data to the relevant Python data types. + +Overview +======== + +The library deals with these concepts: + +.. glossary:: + + Widget + A class that corresponds to an HTML form widget, e.g. + ``<input type="text">`` or ``<textarea>``. This handles rendering of the + widget as HTML. + + Field + A class that is responsible for doing validation, e.g. + an ``EmailField`` that makes sure its data is a valid e-mail address. + + Form + A collection of fields that knows how to validate itself and + display itself as HTML. + + Form Media + The CSS and JavaScript resources that are required to render a form. + +The library is decoupled from the other Django components, such as the database +layer, views and templates. It relies only on Django settings, a couple of +``django.utils`` helper functions and Django's internationalization hooks (but +you're not required to be using internationalization features to use this +library). + +Form objects +============ + +A Form object encapsulates a sequence of form fields and a collection of +validation rules that must be fulfilled in order for the form to be accepted. +Form classes are created as subclasses of ``django.forms.Form`` and +make use of a declarative style that you'll be familiar with if you've used +Django's database models. + +For example, consider a form used to implement "contact me" functionality on a +personal Web site: + +.. code-block:: python + + from django import forms + + class ContactForm(forms.Form): + subject = forms.CharField(max_length=100) + message = forms.CharField() + sender = forms.EmailField() + cc_myself = forms.BooleanField(required=False) + +A form is composed of ``Field`` objects. In this case, our form has four +fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. ``CharField``, +``EmailField`` and ``BooleanField`` are just three of the available field types; +a full list can be found in :doc:`/ref/forms/fields`. + +If your form is going to be used to directly add or edit a Django model, you can +use a :doc:`ModelForm </topics/forms/modelforms>` to avoid duplicating your model +description. + +Using a form in a view +---------------------- + +The standard pattern for processing a form in a view looks like this: + +.. code-block:: python + + def contact(request): + if request.method == 'POST': # If the form has been submitted... + form = ContactForm(request.POST) # A form bound to the POST data + if form.is_valid(): # All validation rules pass + # Process the data in form.cleaned_data + # ... + return HttpResponseRedirect('/thanks/') # Redirect after POST + else: + form = ContactForm() # An unbound form + + return render_to_response('contact.html', { + 'form': form, + }) + + +There are three code paths here: + + 1. If the form has not been submitted, an unbound instance of ContactForm is + created and passed to the template. + 2. If the form has been submitted, a bound instance of the form is created + using ``request.POST``. If the submitted data is valid, it is processed + and the user is re-directed to a "thanks" page. + 3. If the form has been submitted but is invalid, the bound form instance is + passed on to the template. + +.. versionchanged:: 1.0 + The ``cleaned_data`` attribute was called ``clean_data`` in earlier releases. + +The distinction between **bound** and **unbound** forms is important. An unbound +form does not have any data associated with it; when rendered to the user, it +will be empty or will contain default values. A bound form does have submitted +data, and hence can be used to tell if that data is valid. If an invalid bound +form is rendered it can include inline error messages telling the user where +they went wrong. + +See :ref:`ref-forms-api-bound-unbound` for further information on the +differences between bound and unbound forms. + +Handling file uploads with a form +--------------------------------- + +To see how to handle file uploads with your form see +:ref:`binding-uploaded-files` for more information. + +Processing the data from a form +------------------------------- + +Once ``is_valid()`` returns ``True``, you can process the form submission safe +in the knowledge that it conforms to the validation rules defined by your form. +While you could access ``request.POST`` directly at this point, it is better to +access ``form.cleaned_data``. This data has not only been validated but will +also be converted in to the relevant Python types for you. In the above example, +``cc_myself`` will be a boolean value. Likewise, fields such as ``IntegerField`` +and ``FloatField`` convert values to a Python int and float respectively. + +Extending the above example, here's how the form data could be processed: + +.. code-block:: python + + if form.is_valid(): + subject = form.cleaned_data['subject'] + message = form.cleaned_data['message'] + sender = form.cleaned_data['sender'] + cc_myself = form.cleaned_data['cc_myself'] + + recipients = ['info@example.com'] + if cc_myself: + recipients.append(sender) + + from django.core.mail import send_mail + send_mail(subject, message, sender, recipients) + return HttpResponseRedirect('/thanks/') # Redirect after POST + +For more on sending e-mail from Django, see :doc:`/topics/email`. + +Displaying a form using a template +---------------------------------- + +Forms are designed to work with the Django template language. In the above +example, we passed our ``ContactForm`` instance to the template using the +context variable ``form``. Here's a simple example template:: + + <form action="/contact/" method="post"> + {{ form.as_p }} + <input type="submit" value="Submit" /> + </form> + +The form only outputs its own fields; it is up to you to provide the surrounding +``<form>`` tags and the submit button. + +``form.as_p`` will output the form with each form field and accompanying label +wrapped in a paragraph. Here's the output for our example template:: + + <form action="/contact/" method="post"> + <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> + <input type="submit" value="Submit" /> + </form> + +Note that each form field has an ID attribute set to ``id_<field-name>``, which +is referenced by the accompanying label tag. This is important for ensuring +forms are accessible to assistive technology such as screen reader software. You +can also :ref:`customize the way in which labels and ids are generated +<ref-forms-api-configuring-label>`. + +You can also use ``form.as_table`` to output table rows (you'll need to provide +your own ``<table>`` tags) and ``form.as_ul`` to output list items. + +Customizing the form template +----------------------------- + +If the default generated HTML is not to your taste, you can completely customize +the way a form is presented using the Django template language. Extending the +above example:: + + <form action="/contact/" method="post"> + {{ form.non_field_errors }} + <div class="fieldWrapper"> + {{ form.subject.errors }} + <label for="id_subject">E-mail subject:</label> + {{ form.subject }} + </div> + <div class="fieldWrapper"> + {{ form.message.errors }} + <label for="id_message">Your message:</label> + {{ form.message }} + </div> + <div class="fieldWrapper"> + {{ form.sender.errors }} + <label for="id_sender">Your email address:</label> + {{ form.sender }} + </div> + <div class="fieldWrapper"> + {{ form.cc_myself.errors }} + <label for="id_cc_myself">CC yourself?</label> + {{ form.cc_myself }} + </div> + <p><input type="submit" value="Send message" /></p> + </form> + +Each named form-field can be output to the template using +``{{ form.name_of_field }}``, which will produce the HTML needed to display the +form widget. Using ``{{ form.name_of_field.errors }}`` displays a list of form +errors, rendered as an unordered list. This might look like:: + + <ul class="errorlist"> + <li>Sender is required.</li> + </ul> + +The list has a CSS class of ``errorlist`` to allow you to style its appearance. +If you wish to further customize the display of errors you can do so by looping +over them:: + + {% if form.subject.errors %} + <ol> + {% for error in form.subject.errors %} + <li><strong>{{ error|escape }}</strong></li> + {% endfor %} + </ol> + {% endif %} + +Looping over the form's fields +------------------------------ + +If you're using the same HTML for each of your form fields, you can reduce +duplicate code by looping through each field in turn using a ``{% for %}`` +loop:: + + <form action="/contact/" method="post"> + {% for field in form %} + <div class="fieldWrapper"> + {{ field.errors }} + {{ field.label_tag }}: {{ field }} + </div> + {% endfor %} + <p><input type="submit" value="Send message" /></p> + </form> + +Within this loop, ``{{ field }}`` is an instance of :class:`BoundField`. +``BoundField`` also has the following attributes, which can be useful in your +templates: + + ``{{ field.label }}`` + The label of the field, e.g. ``E-mail address``. + + ``{{ field.label_tag }}`` + The field's label wrapped in the appropriate HTML ``<label>`` tag, + e.g. ``<label for="id_email">E-mail address</label>`` + + ``{{ field.html_name }}`` + The name of the field that will be used in the input element's name + field. This takes the form prefix into account, if it has been set. + + ``{{ field.help_text }}`` + Any help text that has been associated with the field. + + ``{{ field.errors }}`` + Outputs a ``<ul class="errorlist">`` containing any validation errors + corresponding to this field. You can customize the presentation of + the errors with a ``{% for error in field.errors %}`` loop. In this + case, each object in the loop is a simple string containing the error + message. + + ``field.is_hidden`` + This attribute is ``True`` if the form field is a hidden field and + ``False`` otherwise. It's not particularly useful as a template + variable, but could be useful in conditional tests such as:: + + {% if field.is_hidden %} + {# Do something special #} + {% endif %} + +Looping over hidden and visible fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're manually laying out a form in a template, as opposed to relying on +Django's default form layout, you might want to treat ``<input type="hidden">`` +fields differently than non-hidden fields. For example, because hidden fields +don't display anything, putting error messages "next to" the field could cause +confusion for your users -- so errors for those fields should be handled +differently. + +Django provides two methods on a form that allow you to loop over the hidden +and visible fields independently: ``hidden_fields()`` and +``visible_fields()``. Here's a modification of an earlier example that uses +these two methods:: + + <form action="/contact/" method="post"> + {% for field in form.visible_fields %} + <div class="fieldWrapper"> + + {# Include the hidden fields in the form #} + {% if forloop.first %} + {% for hidden in form.hidden_fields %} + {{ hidden }} + {% endfor %} + {% endif %} + + {{ field.errors }} + {{ field.label_tag }}: {{ field }} + </div> + {% endfor %} + <p><input type="submit" value="Send message" /></p> + </form> + +This example does not handle any errors in the hidden fields. Usually, an +error in a hidden field is a sign of form tampering, since normal form +interaction won't alter them. However, you could easily insert some error +displays for those form errors, as well. + +.. versionadded:: 1.1 + The ``hidden_fields`` and ``visible_fields`` methods are new in Django + 1.1. + +Reusable form templates +----------------------- + +If your site uses the same rendering logic for forms in multiple places, you +can reduce duplication by saving the form's loop in a standalone template and +using the :ttag:`include` tag to reuse it in other templates:: + + <form action="/contact/" method="post"> + {% include "form_snippet.html" %} + <p><input type="submit" value="Send message" /></p> + </form> + + # In form_snippet.html: + + {% for field in form %} + <div class="fieldWrapper"> + {{ field.errors }} + {{ field.label_tag }}: {{ field }} + </div> + {% endfor %} + +If the form object passed to a template has a different name within the +context, you can alias it using the :ttag:`with` tag:: + + <form action="/comments/add/" method="post"> + {% with comment_form as form %} + {% include "form_snippet.html" %} + {% endwith %} + <p><input type="submit" value="Submit comment" /></p> + </form> + +If you find yourself doing this often, you might consider creating a custom +:ref:`inclusion tag<howto-custom-template-tags-inclusion-tags>`. + +Further topics +============== + +This covers the basics, but forms can do a whole lot more: + +.. toctree:: + :maxdepth: 2 + + modelforms + formsets + media + +.. seealso:: + + :doc:`The Forms Reference </ref/forms/index>` + Covers the full API reference, including form fields, form widgets, + and form and field validation.