diff options
Diffstat (limited to 'parts/django/docs/topics/forms')
-rw-r--r-- | parts/django/docs/topics/forms/formsets.txt | 440 | ||||
-rw-r--r-- | parts/django/docs/topics/forms/index.txt | 402 | ||||
-rw-r--r-- | parts/django/docs/topics/forms/media.txt | 309 | ||||
-rw-r--r-- | parts/django/docs/topics/forms/modelforms.txt | 885 |
4 files changed, 0 insertions, 2036 deletions
diff --git a/parts/django/docs/topics/forms/formsets.txt b/parts/django/docs/topics/forms/formsets.txt deleted file mode 100644 index 72296bc..0000000 --- a/parts/django/docs/topics/forms/formsets.txt +++ /dev/null @@ -1,440 +0,0 @@ -.. _formsets: - -Formsets -======== - -A formset is a layer of abstraction to working with multiple forms on the same -page. It can be best compared to a data grid. Let's say you have the following -form:: - - >>> from django import forms - >>> class ArticleForm(forms.Form): - ... title = forms.CharField() - ... pub_date = forms.DateField() - -You might want to allow the user to create several articles at once. To create -a formset out of an ``ArticleForm`` you would do:: - - >>> from django.forms.formsets import formset_factory - >>> ArticleFormSet = formset_factory(ArticleForm) - -You now have created a formset named ``ArticleFormSet``. The formset gives you -the ability to iterate over the forms in the formset and display them as you -would with a regular form:: - - >>> formset = ArticleFormSet() - >>> for form in formset.forms: - ... print form.as_table() - <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr> - <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr> - -As you can see it only displayed one empty form. The number of empty forms -that is displayed is controlled by the ``extra`` parameter. By default, -``formset_factory`` defines one extra form; the following example will -display two blank forms:: - - >>> ArticleFormSet = formset_factory(ArticleForm, extra=2) - -Using initial data with a formset ---------------------------------- - -Initial data is what drives the main usability of a formset. As shown above -you can define the number of extra forms. What this means is that you are -telling the formset how many additional forms to show in addition to the -number of forms it generates from the initial data. Lets take a look at an -example:: - - >>> ArticleFormSet = formset_factory(ArticleForm, extra=2) - >>> formset = ArticleFormSet(initial=[ - ... {'title': u'Django is now open source', - ... 'pub_date': datetime.date.today()}, - ... ]) - - >>> for form in formset.forms: - ... print form.as_table() - <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title" /></td></tr> - <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date" /></td></tr> - <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr> - <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr> - <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr> - <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr> - -There are now a total of three forms showing above. One for the initial data -that was passed in and two extra forms. Also note that we are passing in a -list of dictionaries as the initial data. - -.. seealso:: - - :ref:`Creating formsets from models with model formsets <model-formsets>`. - -.. _formsets-max-num: - -Limiting the maximum number of forms ------------------------------------- - -The ``max_num`` parameter to ``formset_factory`` gives you the ability to -limit the maximum number of empty forms the formset will display:: - - >>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1) - >>> formset = ArticleFormset() - >>> for form in formset.forms: - ... print form.as_table() - <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr> - <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr> - -.. versionchanged:: 1.2 - -If the value of ``max_num`` is greater than the number of existing -objects, up to ``extra`` additional blank forms will be added to the formset, -so long as the total number of forms does not exceed ``max_num``. - -A ``max_num`` value of ``None`` (the default) puts no limit on the number of -forms displayed. Please note that the default value of ``max_num`` was changed -from ``0`` to ``None`` in version 1.2 to allow ``0`` as a valid value. - -Formset validation ------------------- - -Validation with a formset is almost identical to a regular ``Form``. There is -an ``is_valid`` method on the formset to provide a convenient way to validate -all forms in the formset:: - - >>> ArticleFormSet = formset_factory(ArticleForm) - >>> formset = ArticleFormSet({}) - >>> formset.is_valid() - True - -We passed in no data to the formset which is resulting in a valid form. The -formset is smart enough to ignore extra forms that were not changed. If we -provide an invalid article:: - - >>> data = { - ... 'form-TOTAL_FORMS': u'2', - ... 'form-INITIAL_FORMS': u'0', - ... 'form-MAX_NUM_FORMS': u'', - ... 'form-0-title': u'Test', - ... 'form-0-pub_date': u'16 June 1904', - ... 'form-1-title': u'Test', - ... 'form-1-pub_date': u'', # <-- this date is missing but required - ... } - >>> formset = ArticleFormSet(data) - >>> formset.is_valid() - False - >>> formset.errors - [{}, {'pub_date': [u'This field is required.']}] - -As we can see, ``formset.errors`` is a list whose entries correspond to the -forms in the formset. Validation was performed for each of the two forms, and -the expected error message appears for the second item. - -.. _understanding-the-managementform: - -Understanding the ManagementForm -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You may have noticed the additional data (``form-TOTAL_FORMS``, -``form-INITIAL_FORMS`` and ``form-MAX_NUM_FORMS``) that was required -in the formset's data above. This data is required for the -``ManagementForm``. This form is used by the formset to manage the -collection of forms contained in the formset. If you don't provide -this management data, an exception will be raised:: - - >>> data = { - ... 'form-0-title': u'Test', - ... 'form-0-pub_date': u'', - ... } - >>> formset = ArticleFormSet(data) - Traceback (most recent call last): - ... - django.forms.util.ValidationError: [u'ManagementForm data is missing or has been tampered with'] - -It is used to keep track of how many form instances are being displayed. If -you are adding new forms via JavaScript, you should increment the count fields -in this form as well. - -The management form is available as an attribute of the formset -itself. When rendering a formset in a template, you can include all -the management data by rendering ``{{ my_formset.management_form }}`` -(substituting the name of your formset as appropriate). - -.. versionadded:: 1.1 - -``total_form_count`` and ``initial_form_count`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``BaseFormSet`` has a couple of methods that are closely related to the -``ManagementForm``, ``total_form_count`` and ``initial_form_count``. - -``total_form_count`` returns the total number of forms in this formset. -``initial_form_count`` returns the number of forms in the formset that were -pre-filled, and is also used to determine how many forms are required. You -will probably never need to override either of these methods, so please be -sure you understand what they do before doing so. - -.. versionadded:: 1.2 - -``empty_form`` -~~~~~~~~~~~~~~ - -``BaseFormSet`` provides an additional attribute ``empty_form`` which returns -a form instance with a prefix of ``__prefix__`` for easier use in dynamic -forms with JavaScript. - -Custom formset validation -~~~~~~~~~~~~~~~~~~~~~~~~~ - -A formset has a ``clean`` method similar to the one on a ``Form`` class. This -is where you define your own validation that works at the formset level:: - - >>> from django.forms.formsets import BaseFormSet - - >>> class BaseArticleFormSet(BaseFormSet): - ... def clean(self): - ... """Checks that no two articles have the same title.""" - ... if any(self.errors): - ... # Don't bother validating the formset unless each form is valid on its own - ... return - ... titles = [] - ... for i in range(0, self.total_form_count()): - ... form = self.forms[i] - ... title = form.cleaned_data['title'] - ... if title in titles: - ... raise forms.ValidationError, "Articles in a set must have distinct titles." - ... titles.append(title) - - >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) - >>> data = { - ... 'form-TOTAL_FORMS': u'2', - ... 'form-INITIAL_FORMS': u'0', - ... 'form-MAX_NUM_FORMS': u'', - ... 'form-0-title': u'Test', - ... 'form-0-pub_date': u'16 June 1904', - ... 'form-1-title': u'Test', - ... 'form-1-pub_date': u'23 June 1912', - ... } - >>> formset = ArticleFormSet(data) - >>> formset.is_valid() - False - >>> formset.errors - [{}, {}] - >>> formset.non_form_errors() - [u'Articles in a set must have distinct titles.'] - -The formset ``clean`` method is called after all the ``Form.clean`` methods -have been called. The errors will be found using the ``non_form_errors()`` -method on the formset. - -Dealing with ordering and deletion of forms -------------------------------------------- - -Common use cases with a formset is dealing with ordering and deletion of the -form instances. This has been dealt with for you. The ``formset_factory`` -provides two optional parameters ``can_order`` and ``can_delete`` that will do -the extra work of adding the extra fields and providing simpler ways of -getting to that data. - -``can_order`` -~~~~~~~~~~~~~ - -Default: ``False`` - -Lets create a formset with the ability to order:: - - >>> ArticleFormSet = formset_factory(ArticleForm, can_order=True) - >>> formset = ArticleFormSet(initial=[ - ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, - ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, - ... ]) - >>> for form in formset.forms: - ... print form.as_table() - <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr> - <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr> - <tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="text" name="form-0-ORDER" value="1" id="id_form-0-ORDER" /></td></tr> - <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr> - <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr> - <tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="text" name="form-1-ORDER" value="2" id="id_form-1-ORDER" /></td></tr> - <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr> - <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr> - <tr><th><label for="id_form-2-ORDER">Order:</label></th><td><input type="text" name="form-2-ORDER" id="id_form-2-ORDER" /></td></tr> - -This adds an additional field to each form. This new field is named ``ORDER`` -and is an ``forms.IntegerField``. For the forms that came from the initial -data it automatically assigned them a numeric value. Lets look at what will -happen when the user changes these values:: - - >>> data = { - ... 'form-TOTAL_FORMS': u'3', - ... 'form-INITIAL_FORMS': u'2', - ... 'form-MAX_NUM_FORMS': u'', - ... 'form-0-title': u'Article #1', - ... 'form-0-pub_date': u'2008-05-10', - ... 'form-0-ORDER': u'2', - ... 'form-1-title': u'Article #2', - ... 'form-1-pub_date': u'2008-05-11', - ... 'form-1-ORDER': u'1', - ... 'form-2-title': u'Article #3', - ... 'form-2-pub_date': u'2008-05-01', - ... 'form-2-ORDER': u'0', - ... } - - >>> formset = ArticleFormSet(data, initial=[ - ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, - ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, - ... ]) - >>> formset.is_valid() - True - >>> for form in formset.ordered_forms: - ... print form.cleaned_data - {'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': u'Article #3'} - {'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': u'Article #2'} - {'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': u'Article #1'} - -``can_delete`` -~~~~~~~~~~~~~~ - -Default: ``False`` - -Lets create a formset with the ability to delete:: - - >>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True) - >>> formset = ArticleFormSet(initial=[ - ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, - ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, - ... ]) - >>> for form in formset.forms: - .... print form.as_table() - <input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" /> - <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr> - <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr> - <tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /></td></tr> - <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr> - <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr> - <tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /></td></tr> - <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr> - <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr> - <tr><th><label for="id_form-2-DELETE">Delete:</label></th><td><input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /></td></tr> - -Similar to ``can_order`` this adds a new field to each form named ``DELETE`` -and is a ``forms.BooleanField``. When data comes through marking any of the -delete fields you can access them with ``deleted_forms``:: - - >>> data = { - ... 'form-TOTAL_FORMS': u'3', - ... 'form-INITIAL_FORMS': u'2', - ... 'form-MAX_NUM_FORMS': u'', - ... 'form-0-title': u'Article #1', - ... 'form-0-pub_date': u'2008-05-10', - ... 'form-0-DELETE': u'on', - ... 'form-1-title': u'Article #2', - ... 'form-1-pub_date': u'2008-05-11', - ... 'form-1-DELETE': u'', - ... 'form-2-title': u'', - ... 'form-2-pub_date': u'', - ... 'form-2-DELETE': u'', - ... } - - >>> formset = ArticleFormSet(data, initial=[ - ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, - ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, - ... ]) - >>> [form.cleaned_data for form in formset.deleted_forms] - [{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': u'Article #1'}] - -Adding additional fields to a formset -------------------------------------- - -If you need to add additional fields to the formset this can be easily -accomplished. The formset base class provides an ``add_fields`` method. You -can simply override this method to add your own fields or even redefine the -default fields/attributes of the order and deletion fields:: - - >>> class BaseArticleFormSet(BaseFormSet): - ... def add_fields(self, form, index): - ... super(BaseArticleFormSet, self).add_fields(form, index) - ... form.fields["my_field"] = forms.CharField() - - >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) - >>> formset = ArticleFormSet() - >>> for form in formset.forms: - ... print form.as_table() - <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr> - <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr> - <tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_field" id="id_form-0-my_field" /></td></tr> - -Using a formset in views and templates --------------------------------------- - -Using a formset inside a view is as easy as using a regular ``Form`` class. -The only thing you will want to be aware of is making sure to use the -management form inside the template. Let's look at a sample view: - -.. code-block:: python - - def manage_articles(request): - ArticleFormSet = formset_factory(ArticleForm) - if request.method == 'POST': - formset = ArticleFormSet(request.POST, request.FILES) - if formset.is_valid(): - # do something with the formset.cleaned_data - pass - else: - formset = ArticleFormSet() - return render_to_response('manage_articles.html', {'formset': formset}) - -The ``manage_articles.html`` template might look like this: - -.. code-block:: html+django - - <form method="post" action=""> - {{ formset.management_form }} - <table> - {% for form in formset.forms %} - {{ form }} - {% endfor %} - </table> - </form> - -However the above can be slightly shortcutted and let the formset itself deal -with the management form: - -.. code-block:: html+django - - <form method="post" action=""> - <table> - {{ formset }} - </table> - </form> - -The above ends up calling the ``as_table`` method on the formset class. - -Using more than one formset in a view -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You are able to use more than one formset in a view if you like. Formsets -borrow much of its behavior from forms. With that said you are able to use -``prefix`` to prefix formset form field names with a given value to allow -more than one formset to be sent to a view without name clashing. Lets take -a look at how this might be accomplished: - -.. code-block:: python - - def manage_articles(request): - ArticleFormSet = formset_factory(ArticleForm) - BookFormSet = formset_factory(BookForm) - if request.method == 'POST': - article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles') - book_formset = BookFormSet(request.POST, request.FILES, prefix='books') - if article_formset.is_valid() and book_formset.is_valid(): - # do something with the cleaned_data on the formsets. - pass - else: - article_formset = ArticleFormSet(prefix='articles') - book_formset = BookFormSet(prefix='books') - return render_to_response('manage_articles.html', { - 'article_formset': article_formset, - 'book_formset': book_formset, - }) - -You would then render the formsets as normal. It is important to point out -that you need to pass ``prefix`` on both the POST and non-POST cases so that -it is rendered and processed correctly. diff --git a/parts/django/docs/topics/forms/index.txt b/parts/django/docs/topics/forms/index.txt deleted file mode 100644 index 30b09c0..0000000 --- a/parts/django/docs/topics/forms/index.txt +++ /dev/null @@ -1,402 +0,0 @@ -================== -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. diff --git a/parts/django/docs/topics/forms/media.txt b/parts/django/docs/topics/forms/media.txt deleted file mode 100644 index fe70894..0000000 --- a/parts/django/docs/topics/forms/media.txt +++ /dev/null @@ -1,309 +0,0 @@ -Form Media -========== - -Rendering an attractive and easy-to-use Web form requires more than just -HTML - it also requires CSS stylesheets, and if you want to use fancy -"Web2.0" widgets, you may also need to include some JavaScript on each -page. The exact combination of CSS and JavaScript that is required for -any given page will depend upon the widgets that are in use on that page. - -This is where Django media definitions come in. Django allows you to -associate different media files with the forms and widgets that require -that media. For example, if you want to use a calendar to render DateFields, -you can define a custom Calendar widget. This widget can then be associated -with the CSS and JavaScript that is required to render the calendar. When -the Calendar widget is used on a form, Django is able to identify the CSS and -JavaScript files that are required, and provide the list of file names -in a form suitable for easy inclusion on your Web page. - -.. admonition:: Media and Django Admin - - The Django Admin application defines a number of customized widgets - for calendars, filtered selections, and so on. These widgets define - media requirements, and the Django Admin uses the custom widgets - in place of the Django defaults. The Admin templates will only include - those media files that are required to render the widgets on any - given page. - - If you like the widgets that the Django Admin application uses, - feel free to use them in your own application! They're all stored - in ``django.contrib.admin.widgets``. - -.. admonition:: Which JavaScript toolkit? - - Many JavaScript toolkits exist, and many of them include widgets (such - as calendar widgets) that can be used to enhance your application. - Django has deliberately avoided blessing any one JavaScript toolkit. - Each toolkit has its own relative strengths and weaknesses - use - whichever toolkit suits your requirements. Django is able to integrate - with any JavaScript toolkit. - -Media as a static definition ----------------------------- - -The easiest way to define media is as a static definition. Using this method, -the media declaration is an inner class. The properties of the inner class -define the media requirements. - -Here's a simple example:: - - class CalendarWidget(forms.TextInput): - class Media: - css = { - 'all': ('pretty.css',) - } - js = ('animations.js', 'actions.js') - -This code defines a ``CalendarWidget``, which will be based on ``TextInput``. -Every time the CalendarWidget is used on a form, that form will be directed -to include the CSS file ``pretty.css``, and the JavaScript files -``animations.js`` and ``actions.js``. - -This static media definition is converted at runtime into a widget property -named ``media``. The media for a CalendarWidget instance can be retrieved -through this property:: - - >>> w = CalendarWidget() - >>> print w.media - <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> - <script type="text/javascript" src="http://media.example.com/animations.js"></script> - <script type="text/javascript" src="http://media.example.com/actions.js"></script> - -Here's a list of all possible ``Media`` options. There are no required options. - -``css`` -~~~~~~~ - -A dictionary describing the CSS files required for various forms of output -media. - -The values in the dictionary should be a tuple/list of file names. See -`the section on media paths`_ for details of how to specify paths to media -files. - -.. _the section on media paths: `Paths in media definitions`_ - -The keys in the dictionary are the output media types. These are the same -types accepted by CSS files in media declarations: 'all', 'aural', 'braille', -'embossed', 'handheld', 'print', 'projection', 'screen', 'tty' and 'tv'. If -you need to have different stylesheets for different media types, provide -a list of CSS files for each output medium. The following example would -provide two CSS options -- one for the screen, and one for print:: - - class Media: - css = { - 'screen': ('pretty.css',), - 'print': ('newspaper.css',) - } - -If a group of CSS files are appropriate for multiple output media types, -the dictionary key can be a comma separated list of output media types. -In the following example, TV's and projectors will have the same media -requirements:: - - class Media: - css = { - 'screen': ('pretty.css',), - 'tv,projector': ('lo_res.css',), - 'print': ('newspaper.css',) - } - -If this last CSS definition were to be rendered, it would become the following HTML:: - - <link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" /> - <link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" /> - <link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" /> - -``js`` -~~~~~~ - -A tuple describing the required JavaScript files. See -`the section on media paths`_ for details of how to specify paths to media -files. - -``extend`` -~~~~~~~~~~ - -A boolean defining inheritance behavior for media declarations. - -By default, any object using a static media definition will inherit all the -media associated with the parent widget. This occurs regardless of how the -parent defines its media requirements. For example, if we were to extend our -basic Calendar widget from the example above:: - - >>> class FancyCalendarWidget(CalendarWidget): - ... class Media: - ... css = { - ... 'all': ('fancy.css',) - ... } - ... js = ('whizbang.js',) - - >>> w = FancyCalendarWidget() - >>> print w.media - <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> - <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" /> - <script type="text/javascript" src="http://media.example.com/animations.js"></script> - <script type="text/javascript" src="http://media.example.com/actions.js"></script> - <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> - -The FancyCalendar widget inherits all the media from it's parent widget. If -you don't want media to be inherited in this way, add an ``extend=False`` -declaration to the media declaration:: - - >>> class FancyCalendarWidget(CalendarWidget): - ... class Media: - ... extend = False - ... css = { - ... 'all': ('fancy.css',) - ... } - ... js = ('whizbang.js',) - - >>> w = FancyCalendarWidget() - >>> print w.media - <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" /> - <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> - -If you require even more control over media inheritance, define your media -using a `dynamic property`_. Dynamic properties give you complete control over -which media files are inherited, and which are not. - -.. _dynamic property: `Media as a dynamic property`_ - -Media as a dynamic property ---------------------------- - -If you need to perform some more sophisticated manipulation of media -requirements, you can define the media property directly. This is done -by defining a widget property that returns an instance of ``forms.Media``. -The constructor for ``forms.Media`` accepts ``css`` and ``js`` keyword -arguments in the same format as that used in a static media definition. - -For example, the static media definition for our Calendar Widget could -also be defined in a dynamic fashion:: - - class CalendarWidget(forms.TextInput): - def _media(self): - return forms.Media(css={'all': ('pretty.css',)}, - js=('animations.js', 'actions.js')) - media = property(_media) - -See the section on `Media objects`_ for more details on how to construct -return values for dynamic media properties. - -Paths in media definitions --------------------------- - -Paths used to specify media can be either relative or absolute. If a path -starts with '/', 'http://' or 'https://', it will be interpreted as an absolute -path, and left as-is. All other paths will be prepended with the value of -``settings.MEDIA_URL``. For example, if the MEDIA_URL for your site was -``http://media.example.com/``:: - - class CalendarWidget(forms.TextInput): - class Media: - css = { - 'all': ('/css/pretty.css',), - } - js = ('animations.js', 'http://othersite.com/actions.js') - - >>> w = CalendarWidget() - >>> print w.media - <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" /> - <script type="text/javascript" src="http://media.example.com/animations.js"></script> - <script type="text/javascript" src="http://othersite.com/actions.js"></script> - -Media objects -------------- - -When you interrogate the media attribute of a widget or form, the value that -is returned is a ``forms.Media`` object. As we have already seen, the string -representation of a Media object is the HTML required to include media -in the ``<head>`` block of your HTML page. - -However, Media objects have some other interesting properties. - -Media subsets -~~~~~~~~~~~~~ - -If you only want media of a particular type, you can use the subscript operator -to filter out a medium of interest. For example:: - - >>> w = CalendarWidget() - >>> print w.media - <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> - <script type="text/javascript" src="http://media.example.com/animations.js"></script> - <script type="text/javascript" src="http://media.example.com/actions.js"></script> - - >>> print w.media['css'] - <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> - -When you use the subscript operator, the value that is returned is a new -Media object -- but one that only contains the media of interest. - -Combining media objects -~~~~~~~~~~~~~~~~~~~~~~~ - -Media objects can also be added together. When two media objects are added, -the resulting Media object contains the union of the media from both files:: - - >>> class CalendarWidget(forms.TextInput): - ... class Media: - ... css = { - ... 'all': ('pretty.css',) - ... } - ... js = ('animations.js', 'actions.js') - - >>> class OtherWidget(forms.TextInput): - ... class Media: - ... js = ('whizbang.js',) - - >>> w1 = CalendarWidget() - >>> w2 = OtherWidget() - >>> print w1.media + w2.media - <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> - <script type="text/javascript" src="http://media.example.com/animations.js"></script> - <script type="text/javascript" src="http://media.example.com/actions.js"></script> - <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> - -Media on Forms --------------- - -Widgets aren't the only objects that can have media definitions -- forms -can also define media. The rules for media definitions on forms are the -same as the rules for widgets: declarations can be static or dynamic; -path and inheritance rules for those declarations are exactly the same. - -Regardless of whether you define a media declaration, *all* Form objects -have a media property. The default value for this property is the result -of adding the media definitions for all widgets that are part of the form:: - - >>> class ContactForm(forms.Form): - ... date = DateField(widget=CalendarWidget) - ... name = CharField(max_length=40, widget=OtherWidget) - - >>> f = ContactForm() - >>> f.media - <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> - <script type="text/javascript" src="http://media.example.com/animations.js"></script> - <script type="text/javascript" src="http://media.example.com/actions.js"></script> - <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> - -If you want to associate additional media with a form -- for example, CSS for form -layout -- simply add a media declaration to the form:: - - >>> class ContactForm(forms.Form): - ... date = DateField(widget=CalendarWidget) - ... name = CharField(max_length=40, widget=OtherWidget) - ... - ... class Media: - ... css = { - ... 'all': ('layout.css',) - ... } - - >>> f = ContactForm() - >>> f.media - <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> - <link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" /> - <script type="text/javascript" src="http://media.example.com/animations.js"></script> - <script type="text/javascript" src="http://media.example.com/actions.js"></script> - <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> diff --git a/parts/django/docs/topics/forms/modelforms.txt b/parts/django/docs/topics/forms/modelforms.txt deleted file mode 100644 index 23ed9a7..0000000 --- a/parts/django/docs/topics/forms/modelforms.txt +++ /dev/null @@ -1,885 +0,0 @@ -========================== -Creating forms from models -========================== - -.. module:: django.forms.models - :synopsis: ModelForm and ModelFormset. - -.. currentmodule:: django.forms - -``ModelForm`` -============= -.. class:: ModelForm - -If you're building a database-driven app, chances are you'll have forms that -map closely to Django models. For instance, you might have a ``BlogComment`` -model, and you want to create a form that lets people submit comments. In this -case, it would be redundant to define the field types in your form, because -you've already defined the fields in your model. - -For this reason, Django provides a helper class that let you create a ``Form`` -class from a Django model. - -For example:: - - >>> from django.forms import ModelForm - - # Create the form class. - >>> class ArticleForm(ModelForm): - ... class Meta: - ... model = Article - - # Creating a form to add an article. - >>> form = ArticleForm() - - # Creating a form to change an existing article. - >>> article = Article.objects.get(pk=1) - >>> form = ArticleForm(instance=article) - -Field types ------------ - -The generated ``Form`` class will have a form field for every model field. Each -model field has a corresponding default form field. For example, a -``CharField`` on a model is represented as a ``CharField`` on a form. A -model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is -the full list of conversions: - - =============================== ======================================== - Model field Form field - =============================== ======================================== - ``AutoField`` Not represented in the form - - ``BigIntegerField`` ``IntegerField`` with ``min_value`` set - to -9223372036854775808 and ``max_value`` - set to 9223372036854775807. - - ``BooleanField`` ``BooleanField`` - - ``CharField`` ``CharField`` with ``max_length`` set to - the model field's ``max_length`` - - ``CommaSeparatedIntegerField`` ``CharField`` - - ``DateField`` ``DateField`` - - ``DateTimeField`` ``DateTimeField`` - - ``DecimalField`` ``DecimalField`` - - ``EmailField`` ``EmailField`` - - ``FileField`` ``FileField`` - - ``FilePathField`` ``CharField`` - - ``FloatField`` ``FloatField`` - - ``ForeignKey`` ``ModelChoiceField`` (see below) - - ``ImageField`` ``ImageField`` - - ``IntegerField`` ``IntegerField`` - - ``IPAddressField`` ``IPAddressField`` - - ``ManyToManyField`` ``ModelMultipleChoiceField`` (see - below) - - ``NullBooleanField`` ``CharField`` - - ``PhoneNumberField`` ``USPhoneNumberField`` - (from ``django.contrib.localflavor.us``) - - ``PositiveIntegerField`` ``IntegerField`` - - ``PositiveSmallIntegerField`` ``IntegerField`` - - ``SlugField`` ``SlugField`` - - ``SmallIntegerField`` ``IntegerField`` - - ``TextField`` ``CharField`` with - ``widget=forms.Textarea`` - - ``TimeField`` ``TimeField`` - - ``URLField`` ``URLField`` with ``verify_exists`` set - to the model field's ``verify_exists`` - - ``XMLField`` ``CharField`` with - ``widget=forms.Textarea`` - =============================== ======================================== - - -.. versionadded:: 1.0 - The ``FloatField`` form field and ``DecimalField`` model and form fields - are new in Django 1.0. - -.. versionadded:: 1.2 - The ``BigIntegerField`` is new in Django 1.2. - - -As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field -types are special cases: - - * ``ForeignKey`` is represented by ``django.forms.ModelChoiceField``, - which is a ``ChoiceField`` whose choices are a model ``QuerySet``. - - * ``ManyToManyField`` is represented by - ``django.forms.ModelMultipleChoiceField``, which is a - ``MultipleChoiceField`` whose choices are a model ``QuerySet``. - -In addition, each generated form field has attributes set as follows: - - * If the model field has ``blank=True``, then ``required`` is set to - ``False`` on the form field. Otherwise, ``required=True``. - - * The form field's ``label`` is set to the ``verbose_name`` of the model - field, with the first character capitalized. - - * The form field's ``help_text`` is set to the ``help_text`` of the model - field. - - * If the model field has ``choices`` set, then the form field's ``widget`` - will be set to ``Select``, with choices coming from the model field's - ``choices``. The choices will normally include the blank choice which is - selected by default. If the field is required, this forces the user to - make a selection. The blank choice will not be included if the model - field has ``blank=False`` and an explicit ``default`` value (the - ``default`` value will be initially selected instead). - -Finally, note that you can override the form field used for a given model -field. See `Overriding the default field types or widgets`_ below. - -A full example --------------- - -Consider this set of models:: - - from django.db import models - from django.forms import ModelForm - - TITLE_CHOICES = ( - ('MR', 'Mr.'), - ('MRS', 'Mrs.'), - ('MS', 'Ms.'), - ) - - class Author(models.Model): - name = models.CharField(max_length=100) - title = models.CharField(max_length=3, choices=TITLE_CHOICES) - birth_date = models.DateField(blank=True, null=True) - - def __unicode__(self): - return self.name - - class Book(models.Model): - name = models.CharField(max_length=100) - authors = models.ManyToManyField(Author) - - class AuthorForm(ModelForm): - class Meta: - model = Author - - class BookForm(ModelForm): - class Meta: - model = Book - -With these models, the ``ModelForm`` subclasses above would be roughly -equivalent to this (the only difference being the ``save()`` method, which -we'll discuss in a moment.):: - - class AuthorForm(forms.Form): - name = forms.CharField(max_length=100) - title = forms.CharField(max_length=3, - widget=forms.Select(choices=TITLE_CHOICES)) - birth_date = forms.DateField(required=False) - - class BookForm(forms.Form): - name = forms.CharField(max_length=100) - authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) - -The ``is_valid()`` method and ``errors`` ----------------------------------------- - -.. versionchanged:: 1.2 - -The first time you call ``is_valid()`` or access the ``errors`` attribute of a -``ModelForm`` has always triggered form validation, but as of Django 1.2, it -will also trigger :ref:`model validation <validating-objects>`. This has the -side-effect of cleaning the model you pass to the ``ModelForm`` constructor. -For instance, calling ``is_valid()`` on your form will convert any date fields -on your model to actual date objects. - - -The ``save()`` method ---------------------- - -Every form produced by ``ModelForm`` also has a ``save()`` -method. This method creates and saves a database object from the data -bound to the form. A subclass of ``ModelForm`` can accept an existing -model instance as the keyword argument ``instance``; if this is -supplied, ``save()`` will update that instance. If it's not supplied, -``save()`` will create a new instance of the specified model:: - - # Create a form instance from POST data. - >>> f = ArticleForm(request.POST) - - # Save a new Article object from the form's data. - >>> new_article = f.save() - - # Create a form to edit an existing Article. - >>> a = Article.objects.get(pk=1) - >>> f = ArticleForm(instance=a) - >>> f.save() - - # Create a form to edit an existing Article, but use - # POST data to populate the form. - >>> a = Article.objects.get(pk=1) - >>> f = ArticleForm(request.POST, instance=a) - >>> f.save() - -Note that ``save()`` will raise a ``ValueError`` if the data in the form -doesn't validate -- i.e., if form.errors evaluates to True. - -This ``save()`` method accepts an optional ``commit`` keyword argument, which -accepts either ``True`` or ``False``. If you call ``save()`` with -``commit=False``, then it will return an object that hasn't yet been saved to -the database. In this case, it's up to you to call ``save()`` on the resulting -model instance. This is useful if you want to do custom processing on the -object before saving it, or if you want to use one of the specialized -:ref:`model saving options <ref-models-force-insert>`. ``commit`` is ``True`` -by default. - -Another side effect of using ``commit=False`` is seen when your model has -a many-to-many relation with another model. If your model has a many-to-many -relation and you specify ``commit=False`` when you save a form, Django cannot -immediately save the form data for the many-to-many relation. This is because -it isn't possible to save many-to-many data for an instance until the instance -exists in the database. - -To work around this problem, every time you save a form using ``commit=False``, -Django adds a ``save_m2m()`` method to your ``ModelForm`` subclass. After -you've manually saved the instance produced by the form, you can invoke -``save_m2m()`` to save the many-to-many form data. For example:: - - # Create a form instance with POST data. - >>> f = AuthorForm(request.POST) - - # Create, but don't save the new author instance. - >>> new_author = f.save(commit=False) - - # Modify the author in some way. - >>> new_author.some_field = 'some_value' - - # Save the new instance. - >>> new_author.save() - - # Now, save the many-to-many data for the form. - >>> f.save_m2m() - -Calling ``save_m2m()`` is only required if you use ``save(commit=False)``. -When you use a simple ``save()`` on a form, all data -- including -many-to-many data -- is saved without the need for any additional method calls. -For example:: - - # Create a form instance with POST data. - >>> a = Author() - >>> f = AuthorForm(request.POST, instance=a) - - # Create and save the new author instance. There's no need to do anything else. - >>> new_author = f.save() - -Other than the ``save()`` and ``save_m2m()`` methods, a ``ModelForm`` works -exactly the same way as any other ``forms`` form. For example, the -``is_valid()`` method is used to check for validity, the ``is_multipart()`` -method is used to determine whether a form requires multipart file upload (and -hence whether ``request.FILES`` must be passed to the form), etc. See -:ref:`binding-uploaded-files` for more information. - -Using a subset of fields on the form ------------------------------------- - -In some cases, you may not want all the model fields to appear on the generated -form. There are three ways of telling ``ModelForm`` to use only a subset of the -model fields: - -1. Set ``editable=False`` on the model field. As a result, *any* form - created from the model via ``ModelForm`` will not include that - field. - -2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta`` - class. This attribute, if given, should be a list of field names - to include in the form. - - .. versionchanged:: 1.1 - - The form will render the fields in the same order they are specified in the - ``fields`` attribute. - -3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta`` - class. This attribute, if given, should be a list of field names - to exclude from the form. - -For example, if you want a form for the ``Author`` model (defined -above) that includes only the ``name`` and ``title`` fields, you would -specify ``fields`` or ``exclude`` like this:: - - class PartialAuthorForm(ModelForm): - class Meta: - model = Author - fields = ('name', 'title') - - class PartialAuthorForm(ModelForm): - class Meta: - model = Author - exclude = ('birth_date',) - -Since the Author model has only 3 fields, 'name', 'title', and -'birth_date', the forms above will contain exactly the same fields. - -.. note:: - - If you specify ``fields`` or ``exclude`` when creating a form with - ``ModelForm``, then the fields that are not in the resulting form will not - be set by the form's ``save()`` method. Django will prevent any attempt to - save an incomplete model, so if the model does not allow the missing fields - to be empty, and does not provide a default value for the missing fields, - any attempt to ``save()`` a ``ModelForm`` with missing fields will fail. - To avoid this failure, you must instantiate your model with initial values - for the missing, but required fields:: - - author = Author(title='Mr') - form = PartialAuthorForm(request.POST, instance=author) - form.save() - - Alternatively, you can use ``save(commit=False)`` and manually set - any extra required fields:: - - form = PartialAuthorForm(request.POST) - author = form.save(commit=False) - author.title = 'Mr' - author.save() - - See the `section on saving forms`_ for more details on using - ``save(commit=False)``. - -.. _section on saving forms: `The save() method`_ - -Overriding the default field types or widgets ---------------------------------------------- - -.. versionadded:: 1.2 - The ``widgets`` attribute is new in Django 1.2. - -The default field types, as described in the `Field types`_ table above, are -sensible defaults. If you have a ``DateField`` in your model, chances are you'd -want that to be represented as a ``DateField`` in your form. But -``ModelForm`` gives you the flexibility of changing the form field type and -widget for a given model field. - -To specify a custom widget for a field, use the ``widgets`` attribute of the -inner ``Meta`` class. This should be a dictionary mapping field names to widget -classes or instances. - -For example, if you want the a ``CharField`` for the ``name`` -attribute of ``Author`` to be represented by a ``<textarea>`` instead -of its default ``<input type="text">``, you can override the field's -widget:: - - from django.forms import ModelForm, Textarea - - class AuthorForm(ModelForm): - class Meta: - model = Author - fields = ('name', 'title', 'birth_date') - widgets = { - 'name': Textarea(attrs={'cols': 80, 'rows': 20}), - } - -The ``widgets`` dictionary accepts either widget instances (e.g., -``Textarea(...)``) or classes (e.g., ``Textarea``). - -If you want to further customize a field -- including its type, label, etc. -- -you can do this by declaratively specifying fields like you would in a regular -``Form``. Declared fields will override the default ones generated by using the -``model`` attribute. - -For example, if you wanted to use ``MyDateFormField`` for the ``pub_date`` -field, you could do the following:: - - class ArticleForm(ModelForm): - pub_date = MyDateFormField() - - class Meta: - model = Article - -If you want to override a field's default label, then specify the ``label`` -parameter when declaring the form field:: - - >>> class ArticleForm(ModelForm): - ... pub_date = DateField(label='Publication date') - ... - ... class Meta: - ... model = Article - -.. note:: - - If you explicitly instantiate a form field like this, Django assumes that you - want to completely define its behavior; therefore, default attributes (such as - ``max_length`` or ``required``) are not drawn from the corresponding model. If - you want to maintain the behavior specified in the model, you must set the - relevant arguments explicitly when declaring the form field. - - For example, if the ``Article`` model looks like this:: - - class Article(models.Model): - headline = models.CharField(max_length=200, null=True, blank=True, - help_text="Use puns liberally") - content = models.TextField() - - and you want to do some custom validation for ``headline``, while keeping - the ``blank`` and ``help_text`` values as specified, you might define - ``ArticleForm`` like this:: - - class ArticleForm(ModelForm): - headline = MyFormField(max_length=200, required=False, - help_text="Use puns liberally") - - class Meta: - model = Article - - See the :doc:`form field documentation </ref/forms/fields>` for more information - on fields and their arguments. - -Changing the order of fields ----------------------------- - -.. versionadded:: 1.1 - -By default, a ``ModelForm`` will render fields in the same order that they are -defined on the model, with ``ManyToManyField`` instances appearing last. If -you want to change the order in which fields are rendered, you can use the -``fields`` attribute on the ``Meta`` class. - -The ``fields`` attribute defines the subset of model fields that will be -rendered, and the order in which they will be rendered. For example given this -model:: - - class Book(models.Model): - author = models.ForeignKey(Author) - title = models.CharField(max_length=100) - -the ``author`` field would be rendered first. If we wanted the title field -to be rendered first, we could specify the following ``ModelForm``:: - - >>> class BookForm(ModelForm): - ... class Meta: - ... model = Book - ... fields = ('title', 'author') - -.. _overriding-modelform-clean-method: - -Overriding the clean() method ------------------------------ - -You can override the ``clean()`` method on a model form to provide additional -validation in the same way you can on a normal form. - -In this regard, model forms have two specific characteristics when compared to -forms: - -By default the ``clean()`` method validates the uniqueness of fields that are -marked as ``unique``, ``unique_together`` or ``unique_for_date|month|year`` on -the model. Therefore, if you would like to override the ``clean()`` method and -maintain the default validation, you must call the parent class's ``clean()`` -method. - -Also, a model form instance bound to a model object will contain a -``self.instance`` attribute that gives model form methods access to that -specific model instance. - -Form inheritance ----------------- - -As with basic forms, you can extend and reuse ``ModelForms`` by inheriting -them. This is useful if you need to declare extra fields or extra methods on a -parent class for use in a number of forms derived from models. For example, -using the previous ``ArticleForm`` class:: - - >>> class EnhancedArticleForm(ArticleForm): - ... def clean_pub_date(self): - ... ... - -This creates a form that behaves identically to ``ArticleForm``, except there's -some extra validation and cleaning for the ``pub_date`` field. - -You can also subclass the parent's ``Meta`` inner class if you want to change -the ``Meta.fields`` or ``Meta.excludes`` lists:: - - >>> class RestrictedArticleForm(EnhancedArticleForm): - ... class Meta(ArticleForm.Meta): - ... exclude = ('body',) - -This adds the extra method from the ``EnhancedArticleForm`` and modifies -the original ``ArticleForm.Meta`` to remove one field. - -There are a couple of things to note, however. - - * Normal Python name resolution rules apply. If you have multiple base - classes that declare a ``Meta`` inner class, only the first one will be - used. This means the child's ``Meta``, if it exists, otherwise the - ``Meta`` of the first parent, etc. - - * For technical reasons, a subclass cannot inherit from both a ``ModelForm`` - and a ``Form`` simultaneously. - -Chances are these notes won't affect you unless you're trying to do something -tricky with subclassing. - -Interaction with model validation ---------------------------------- - -As part of its validation process, ``ModelForm`` will call the ``clean()`` -method of each field on your model that has a corresponding field on your form. -If you have excluded any model fields, validation will not be run on those -fields. See the :doc:`form validation </ref/forms/validation>` documentation -for more on how field cleaning and validation work. Also, your model's -``clean()`` method will be called before any uniqueness checks are made. See -:ref:`Validating objects <validating-objects>` for more information on the -model's ``clean()`` hook. - -.. _model-formsets: - -Model formsets -============== - -Like :doc:`regular formsets </topics/forms/formsets>`, Django provides a couple -of enhanced formset classes that make it easy to work with Django models. Let's -reuse the ``Author`` model from above:: - - >>> from django.forms.models import modelformset_factory - >>> AuthorFormSet = modelformset_factory(Author) - -This will create a formset that is capable of working with the data associated -with the ``Author`` model. It works just like a regular formset:: - - >>> formset = AuthorFormSet() - >>> print formset - <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" /> - <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr> - <tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title"> - <option value="" selected="selected">---------</option> - <option value="MR">Mr.</option> - <option value="MRS">Mrs.</option> - <option value="MS">Ms.</option> - </select></td></tr> - <tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0-birth_date" id="id_form-0-birth_date" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr> - -.. note:: - ``modelformset_factory`` uses ``formset_factory`` to generate formsets. - This means that a model formset is just an extension of a basic formset - that knows how to interact with a particular model. - -Changing the queryset ---------------------- - -By default, when you create a formset from a model, the formset will use a -queryset that includes all objects in the model (e.g., -``Author.objects.all()``). You can override this behavior by using the -``queryset`` argument:: - - >>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O')) - -Alternatively, you can create a subclass that sets ``self.queryset`` in -``__init__``:: - - from django.forms.models import BaseModelFormSet - - class BaseAuthorFormSet(BaseModelFormSet): - def __init__(self, *args, **kwargs): - super(BaseAuthorFormSet, self).__init__(*args, **kwargs) - self.queryset = Author.objects.filter(name__startswith='O') - -Then, pass your ``BaseAuthorFormSet`` class to the factory function:: - - >>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet) - -If you want to return a formset that doesn't include *any* pre-existing -instances of the model, you can specify an empty QuerySet:: - - >>> AuthorFormSet(queryset=Author.objects.none()) - - -Controlling which fields are used with ``fields`` and ``exclude`` ------------------------------------------------------------------ - -By default, a model formset uses all fields in the model that are not marked -with ``editable=False``. However, this can be overridden at the formset level:: - - >>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title')) - -Using ``fields`` restricts the formset to use only the given fields. -Alternatively, you can take an "opt-out" approach, specifying which fields to -exclude:: - - >>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',)) - -.. _saving-objects-in-the-formset: - -Saving objects in the formset ------------------------------ - -As with a ``ModelForm``, you can save the data as a model object. This is done -with the formset's ``save()`` method:: - - # Create a formset instance with POST data. - >>> formset = AuthorFormSet(request.POST) - - # Assuming all is valid, save the data. - >>> instances = formset.save() - -The ``save()`` method returns the instances that have been saved to the -database. If a given instance's data didn't change in the bound data, the -instance won't be saved to the database and won't be included in the return -value (``instances``, in the above example). - -Pass ``commit=False`` to return the unsaved model instances:: - - # don't save to the database - >>> instances = formset.save(commit=False) - >>> for instance in instances: - ... # do something with instance - ... instance.save() - -This gives you the ability to attach data to the instances before saving them -to the database. If your formset contains a ``ManyToManyField``, you'll also -need to call ``formset.save_m2m()`` to ensure the many-to-many relationships -are saved properly. - -.. _model-formsets-max-num: - -Limiting the number of editable objects ---------------------------------------- - -.. versionchanged:: 1.2 - -As with regular formsets, you can use the ``max_num`` and ``extra`` parameters -to ``modelformset_factory`` to limit the number of extra forms displayed. - -``max_num`` does not prevent existing objects from being displayed:: - - >>> Author.objects.order_by('name') - [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>] - - >>> AuthorFormSet = modelformset_factory(Author, max_num=1) - >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name')) - >>> [x.name for x in formset.get_queryset()] - [u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman'] - -If the value of ``max_num`` is greater than the number of existing related -objects, up to ``extra`` additional blank forms will be added to the formset, -so long as the total number of forms does not exceed ``max_num``:: - - >>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2) - >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name')) - >>> for form in formset.forms: - ... print form.as_table() - <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr> - <tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100" /><input type="hidden" name="form-1-id" value="3" id="id_form-1-id" /></td></tr> - <tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100" /><input type="hidden" name="form-2-id" value="2" id="id_form-2-id" /></td></tr> - <tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></td></tr> - -.. versionchanged:: 1.2 - -A ``max_num`` value of ``None`` (the default) puts no limit on the number of -forms displayed. - -Using a model formset in a view -------------------------------- - -Model formsets are very similar to formsets. Let's say we want to present a -formset to edit ``Author`` model instances:: - - def manage_authors(request): - AuthorFormSet = modelformset_factory(Author) - if request.method == 'POST': - formset = AuthorFormSet(request.POST, request.FILES) - if formset.is_valid(): - formset.save() - # do something. - else: - formset = AuthorFormSet() - return render_to_response("manage_authors.html", { - "formset": formset, - }) - -As you can see, the view logic of a model formset isn't drastically different -than that of a "normal" formset. The only difference is that we call -``formset.save()`` to save the data into the database. (This was described -above, in :ref:`saving-objects-in-the-formset`.) - -Overiding ``clean()`` on a ``model_formset`` --------------------------------------------- - -Just like with ``ModelForms``, by default the ``clean()`` method of a -``model_formset`` will validate that none of the items in the formset violate -the unique constraints on your model (either ``unique``, ``unique_together`` or -``unique_for_date|month|year``). If you want to overide the ``clean()`` method -on a ``model_formset`` and maintain this validation, you must call the parent -class's ``clean`` method:: - - class MyModelFormSet(BaseModelFormSet): - def clean(self): - super(MyModelFormSet, self).clean() - # example custom validation across forms in the formset: - for form in self.forms: - # your custom formset validation - -Using a custom queryset ------------------------ - -As stated earlier, you can override the default queryset used by the model -formset:: - - def manage_authors(request): - AuthorFormSet = modelformset_factory(Author) - if request.method == "POST": - formset = AuthorFormSet(request.POST, request.FILES, - queryset=Author.objects.filter(name__startswith='O')) - if formset.is_valid(): - formset.save() - # Do something. - else: - formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O')) - return render_to_response("manage_authors.html", { - "formset": formset, - }) - -Note that we pass the ``queryset`` argument in both the ``POST`` and ``GET`` -cases in this example. - -Using the formset in the template ---------------------------------- - -.. highlight:: html+django - -There are three ways to render a formset in a Django template. - -First, you can let the formset do most of the work:: - - <form method="post" action=""> - {{ formset }} - </form> - -Second, you can manually render the formset, but let the form deal with -itself:: - - <form method="post" action=""> - {{ formset.management_form }} - {% for form in formset.forms %} - {{ form }} - {% endfor %} - </form> - -When you manually render the forms yourself, be sure to render the management -form as shown above. See the :ref:`management form documentation -<understanding-the-managementform>`. - -Third, you can manually render each field:: - - <form method="post" action=""> - {{ formset.management_form }} - {% for form in formset.forms %} - {% for field in form %} - {{ field.label_tag }}: {{ field }} - {% endfor %} - {% endfor %} - </form> - -If you opt to use this third method and you don't iterate over the fields with -a ``{% for %}`` loop, you'll need to render the primary key field. For example, -if you were rendering the ``name`` and ``age`` fields of a model:: - - <form method="post" action=""> - {{ formset.management_form }} - {% for form in formset.forms %} - {{ form.id }} - <ul> - <li>{{ form.name }}</li> - <li>{{ form.age }}</li> - </ul> - {% endfor %} - </form> - -Notice how we need to explicitly render ``{{ form.id }}``. This ensures that -the model formset, in the ``POST`` case, will work correctly. (This example -assumes a primary key named ``id``. If you've explicitly defined your own -primary key that isn't called ``id``, make sure it gets rendered.) - -.. highlight:: python - -Inline formsets -=============== - -Inline formsets is a small abstraction layer on top of model formsets. These -simplify the case of working with related objects via a foreign key. Suppose -you have these two models:: - - class Author(models.Model): - name = models.CharField(max_length=100) - - class Book(models.Model): - author = models.ForeignKey(Author) - title = models.CharField(max_length=100) - -If you want to create a formset that allows you to edit books belonging to -a particular author, you could do this:: - - >>> from django.forms.models import inlineformset_factory - >>> BookFormSet = inlineformset_factory(Author, Book) - >>> author = Author.objects.get(name=u'Mike Royko') - >>> formset = BookFormSet(instance=author) - -.. note:: - ``inlineformset_factory`` uses ``modelformset_factory`` and marks - ``can_delete=True``. - -More than one foreign key to the same model -------------------------------------------- - -If your model contains more than one foreign key to the same model, you'll -need to resolve the ambiguity manually using ``fk_name``. For example, consider -the following model:: - - class Friendship(models.Model): - from_friend = models.ForeignKey(Friend) - to_friend = models.ForeignKey(Friend) - length_in_months = models.IntegerField() - -To resolve this, you can use ``fk_name`` to ``inlineformset_factory``:: - - >>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend") - -Using an inline formset in a view ---------------------------------- - -You may want to provide a view that allows a user to edit the related objects -of a model. Here's how you can do that:: - - def manage_books(request, author_id): - author = Author.objects.get(pk=author_id) - BookInlineFormSet = inlineformset_factory(Author, Book) - if request.method == "POST": - formset = BookInlineFormSet(request.POST, request.FILES, instance=author) - if formset.is_valid(): - formset.save() - # Do something. - else: - formset = BookInlineFormSet(instance=author) - return render_to_response("manage_books.html", { - "formset": formset, - }) - -Notice how we pass ``instance`` in both the ``POST`` and ``GET`` cases. |