From bfab9d62ee815baac34b1872676ad26af91c7d94 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Fri, 5 Dec 2008 04:22:00 +0000 Subject: [PATCH] Added a way to iterate over hidden/visible fields in a form. Useful for manual form layout. git-svn-id: http://code.djangoproject.com/svn/django/trunk@9569 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/forms/forms.py | 16 ++++++++- docs/topics/forms/index.txt | 50 ++++++++++++++++++++++++++++ tests/regressiontests/forms/forms.py | 12 +++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/django/forms/forms.py b/django/forms/forms.py index e28479fb8b..29c4f31115 100644 --- a/django/forms/forms.py +++ b/django/forms/forms.py @@ -303,6 +303,20 @@ class BaseForm(StrAndUnicode): return True return False + def hidden_fields(self): + """ + Returns a list of all the BoundField objects that correspond to hidden + fields in the HTML output. Useful for manual form layout in templates. + """ + return [field for field in self if field.is_hidden] + + def visible_fields(self): + """ + Returns a lits of BoundField objects that do not correspond to hidden + fields. The opposite of the hidden_fields() method. + """ + return [field for field in self if not field.is_hidden] + class Form(BaseForm): "A collection of Fields, plus their associated data." # This is a separate class from BaseForm in order to abstract the way @@ -363,7 +377,7 @@ class BoundField(StrAndUnicode): else: name = self.html_initial_name return widget.render(name, data, attrs=attrs) - + def as_text(self, attrs=None, **kwargs): """ Returns a string of HTML for representing this as an . diff --git a/docs/topics/forms/index.txt b/docs/topics/forms/index.txt index 1298ac3987..6cab5b5b90 100644 --- a/docs/topics/forms/index.txt +++ b/docs/topics/forms/index.txt @@ -292,6 +292,56 @@ templates: case, each object in the loop is a simple string containing the error message. + ``field.is_hidden`` + This attribute is ``True`` is 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 are manually laying out a form in a template, you will often want to +work with any hidden fields in a single loop and then treat the visible fields +differently. For example, since hidden fields don't display anything, putting +their error messages "next to" the field isn't going to be very clear to the +reader. So you need to handle errors for those fields a bit 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()``. In a template, you might use these like this (this is a +modification of an earlier example):: + +
+ {% for field in form.visible_fields %} +
+ + {# Include the hidden fields in the form #} + {% if forloop.first %} + {% for hidden in form.hidden_fields %} + {{ field }} + {% endfor %} + {% endif %} + + {{ field.errors }} + {{ field.label_tag }}: {{ field }} +
+ {% endfor %} +

+
+ +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 ----------------------- diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py index 6bee94e579..642cd203ca 100644 --- a/tests/regressiontests/forms/forms.py +++ b/tests/regressiontests/forms/forms.py @@ -1757,4 +1757,16 @@ initial that returns False on a boolean call needs to be treated literally. >>> form.is_valid() True +# Extracting hidden and visible fields ###################################### + +>>> class SongForm(Form): +... token = CharField(widget=HiddenInput) +... artist = CharField() +... name = CharField() +>>> form = SongForm() +>>> [f.name for f in form.hidden_fields()] +['token'] +>>> [f.name for f in form.visible_fields()] +['artist', 'name'] + """