Skip to content

Commit d3f5f21

Browse files
committed
Fixes #10427 -- Abstract the value generation of a BoundField
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14734 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent e74edb4 commit d3f5f21

File tree

3 files changed

+86
-52
lines changed

3 files changed

+86
-52
lines changed

django/forms/forms.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -432,20 +432,11 @@ def as_widget(self, widget=None, attrs=None, only_initial=False):
432432
else:
433433
attrs['id'] = self.html_initial_id
434434

435-
if not self.form.is_bound:
436-
data = self.form.initial.get(self.name, self.field.initial)
437-
if callable(data):
438-
data = data()
439-
else:
440-
data = self.field.bound_data(
441-
self.data, self.form.initial.get(self.name, self.field.initial))
442-
data = self.field.prepare_value(data)
443-
444435
if not only_initial:
445436
name = self.html_name
446437
else:
447438
name = self.html_initial_name
448-
return widget.render(name, data, attrs=attrs)
439+
return widget.render(name, self.value(), attrs=attrs)
449440

450441
def as_text(self, attrs=None, **kwargs):
451442
"""
@@ -470,6 +461,21 @@ def _data(self):
470461
return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name)
471462
data = property(_data)
472463

464+
def value(self):
465+
"""
466+
Returns the value for this BoundField, using the initial value if
467+
the form is not bound or the data otherwise.
468+
"""
469+
if not self.form.is_bound:
470+
data = self.form.initial.get(self.name, self.field.initial)
471+
if callable(data):
472+
data = data()
473+
else:
474+
data = self.field.bound_data(
475+
self.data, self.form.initial.get(self.name, self.field.initial)
476+
)
477+
return self.field.prepare_value(data)
478+
473479
def label_tag(self, contents=None, attrs=None):
474480
"""
475481
Wraps the given contents in a <label>, if the field has an ID attribute.

docs/ref/forms/api.txt

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -584,36 +584,29 @@ More granular output
584584
The ``as_p()``, ``as_ul()`` and ``as_table()`` methods are simply shortcuts for
585585
lazy developers -- they're not the only way a form object can be displayed.
586586

587-
To display the HTML for a single field in your form, use dictionary lookup
588-
syntax using the field's name as the key, and print the resulting object::
587+
.. class:: BoundField
589588

590-
>>> f = ContactForm()
591-
>>> print f['subject']
592-
<input id="id_subject" type="text" name="subject" maxlength="100" />
593-
>>> print f['message']
594-
<input type="text" name="message" id="id_message" />
595-
>>> print f['sender']
596-
<input type="text" name="sender" id="id_sender" />
597-
>>> print f['cc_myself']
598-
<input type="checkbox" name="cc_myself" id="id_cc_myself" />
589+
Used to display HTML or access attributes for a single field of a
590+
:class:`Form` instance.
591+
592+
The :meth:`__unicode__` and :meth:`__str__` methods of this object displays
593+
the HTML for this field.
599594

600-
Call ``str()`` or ``unicode()`` on the field to get its rendered HTML as a
601-
string or Unicode object, respectively::
595+
To retrieve a single ``BoundField``, use dictionary lookup syntax on your form
596+
using the field's name as the key::
602597

603-
>>> str(f['subject'])
604-
'<input id="id_subject" type="text" name="subject" maxlength="100" />'
605-
>>> unicode(f['subject'])
606-
u'<input id="id_subject" type="text" name="subject" maxlength="100" />'
598+
>>> form = ContactForm()
599+
>>> print form['subject']
600+
<input id="id_subject" type="text" name="subject" maxlength="100" />
607601

608-
Form objects define a custom ``__iter__()`` method, which allows you to loop
609-
through their fields::
602+
To retrieve all ``BoundField`` objects, iterate the form::
610603

611-
>>> f = ContactForm()
612-
>>> for field in f: print field
613-
<input id="id_subject" type="text" name="subject" maxlength="100" />
614-
<input type="text" name="message" id="id_message" />
615-
<input type="text" name="sender" id="id_sender" />
616-
<input type="checkbox" name="cc_myself" id="id_cc_myself" />
604+
>>> form = ContactForm()
605+
>>> for boundfield in form: print boundfield
606+
<input id="id_subject" type="text" name="subject" maxlength="100" />
607+
<input type="text" name="message" id="id_message" />
608+
<input type="text" name="sender" id="id_sender" />
609+
<input type="checkbox" name="cc_myself" id="id_cc_myself" />
617610

618611
The field-specific output honors the form object's ``auto_id`` setting::
619612

@@ -624,26 +617,31 @@ The field-specific output honors the form object's ``auto_id`` setting::
624617
>>> print f['message']
625618
<input type="text" name="message" id="id_message" />
626619

627-
For a field's list of errors, access the field's ``errors`` attribute. This
628-
is a list-like object that is displayed as an HTML ``<ul class="errorlist">``
629-
when printed::
620+
For a field's list of errors, access the field's ``errors`` attribute.
630621

631-
>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
632-
>>> f = ContactForm(data, auto_id=False)
633-
>>> print f['message']
634-
<input type="text" name="message" />
635-
>>> f['message'].errors
636-
[u'This field is required.']
637-
>>> print f['message'].errors
638-
<ul class="errorlist"><li>This field is required.</li></ul>
639-
>>> f['subject'].errors
640-
[]
641-
>>> print f['subject'].errors
622+
.. attribute:: BoundField.errors
642623

643-
>>> str(f['subject'].errors)
644-
''
624+
A list-like object that is displayed as an HTML ``<ul class="errorlist">``
625+
when printed::
645626

646-
.. versionadded:: 1.2
627+
>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
628+
>>> f = ContactForm(data, auto_id=False)
629+
>>> print f['message']
630+
<input type="text" name="message" />
631+
>>> f['message'].errors
632+
[u'This field is required.']
633+
>>> print f['message'].errors
634+
<ul class="errorlist"><li>This field is required.</li></ul>
635+
>>> f['subject'].errors
636+
[]
637+
>>> print f['subject'].errors
638+
639+
>>> str(f['subject'].errors)
640+
''
641+
642+
.. method:: BoundField.css_classes()
643+
644+
.. versionadded:: 1.2
647645

648646
When you use Django's rendering shortcuts, CSS classes are used to
649647
indicate required form fields or fields that contain errors. If you're
@@ -662,6 +660,21 @@ those classes as an argument::
662660
>>> f['message'].css_classes('foo bar')
663661
'foo bar required'
664662

663+
.. method:: BoundField.values()
664+
665+
.. versionadded:: 1.3
666+
667+
Use this method to render the raw value of this field as it would be rendered
668+
by a ``Widget``::
669+
670+
>>> initial = {'subject': 'welcome'}
671+
>>> unbound_form = ContactForm(initial=initial)
672+
>>> bound_form = ContactForm(data, initial=initial)
673+
>>> print unbound_form['subject'].value
674+
welcome
675+
>>> print bound_form['subject'].value
676+
hi
677+
665678
.. _binding-uploaded-files:
666679

667680
Binding uploaded files to a form

tests/regressiontests/forms/tests/forms.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,21 @@ class UserRegistration(Form):
11511151
<option value="w">whiz</option>
11521152
</select></li>""")
11531153

1154+
def test_boundfield_values(self):
1155+
# It's possible to get to the value which would be used for rendering
1156+
# the widget for a field by using the BoundField's value method.
1157+
1158+
class UserRegistration(Form):
1159+
username = CharField(max_length=10, initial='djangonaut')
1160+
password = CharField(widget=PasswordInput)
1161+
1162+
unbound = UserRegistration()
1163+
bound = UserRegistration({'password': 'foo'})
1164+
self.assertEqual(bound['username'].value(), None)
1165+
self.assertEqual(unbound['username'].value(), 'djangonaut')
1166+
self.assertEqual(bound['password'].value(), 'foo')
1167+
self.assertEqual(unbound['password'].value(), None)
1168+
11541169
def test_help_text(self):
11551170
# You can specify descriptive text for a field by using the 'help_text' argument)
11561171
class UserRegistration(Form):

0 commit comments

Comments
 (0)