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
This commit is contained in:
Chris Beaven 2010-11-28 02:50:31 +00:00
parent e74edb4d53
commit d3f5f219f5
3 changed files with 86 additions and 52 deletions

View File

@ -432,20 +432,11 @@ class BoundField(StrAndUnicode):
else: else:
attrs['id'] = self.html_initial_id attrs['id'] = self.html_initial_id
if not self.form.is_bound:
data = self.form.initial.get(self.name, self.field.initial)
if callable(data):
data = data()
else:
data = self.field.bound_data(
self.data, self.form.initial.get(self.name, self.field.initial))
data = self.field.prepare_value(data)
if not only_initial: if not only_initial:
name = self.html_name name = self.html_name
else: else:
name = self.html_initial_name name = self.html_initial_name
return widget.render(name, data, attrs=attrs) return widget.render(name, self.value(), attrs=attrs)
def as_text(self, attrs=None, **kwargs): def as_text(self, attrs=None, **kwargs):
""" """
@ -470,6 +461,21 @@ class BoundField(StrAndUnicode):
return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name) return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name)
data = property(_data) data = property(_data)
def value(self):
"""
Returns the value for this BoundField, using the initial value if
the form is not bound or the data otherwise.
"""
if not self.form.is_bound:
data = self.form.initial.get(self.name, self.field.initial)
if callable(data):
data = data()
else:
data = self.field.bound_data(
self.data, self.form.initial.get(self.name, self.field.initial)
)
return self.field.prepare_value(data)
def label_tag(self, contents=None, attrs=None): def label_tag(self, contents=None, attrs=None):
""" """
Wraps the given contents in a <label>, if the field has an ID attribute. Wraps the given contents in a <label>, if the field has an ID attribute.

View File

@ -584,36 +584,29 @@ More granular output
The ``as_p()``, ``as_ul()`` and ``as_table()`` methods are simply shortcuts for The ``as_p()``, ``as_ul()`` and ``as_table()`` methods are simply shortcuts for
lazy developers -- they're not the only way a form object can be displayed. lazy developers -- they're not the only way a form object can be displayed.
To display the HTML for a single field in your form, use dictionary lookup .. class:: BoundField
syntax using the field's name as the key, and print the resulting object::
>>> f = ContactForm() Used to display HTML or access attributes for a single field of a
>>> print f['subject'] :class:`Form` instance.
<input id="id_subject" type="text" name="subject" maxlength="100" />
>>> print f['message'] The :meth:`__unicode__` and :meth:`__str__` methods of this object displays
<input type="text" name="message" id="id_message" /> the HTML for this field.
>>> print f['sender']
<input type="text" name="sender" id="id_sender" />
>>> print f['cc_myself']
<input type="checkbox" name="cc_myself" id="id_cc_myself" />
Call ``str()`` or ``unicode()`` on the field to get its rendered HTML as a To retrieve a single ``BoundField``, use dictionary lookup syntax on your form
string or Unicode object, respectively:: using the field's name as the key::
>>> str(f['subject']) >>> form = ContactForm()
'<input id="id_subject" type="text" name="subject" maxlength="100" />' >>> print form['subject']
>>> unicode(f['subject']) <input id="id_subject" type="text" name="subject" maxlength="100" />
u'<input id="id_subject" type="text" name="subject" maxlength="100" />'
Form objects define a custom ``__iter__()`` method, which allows you to loop To retrieve all ``BoundField`` objects, iterate the form::
through their fields::
>>> f = ContactForm() >>> form = ContactForm()
>>> for field in f: print field >>> for boundfield in form: print boundfield
<input id="id_subject" type="text" name="subject" maxlength="100" /> <input id="id_subject" type="text" name="subject" maxlength="100" />
<input type="text" name="message" id="id_message" /> <input type="text" name="message" id="id_message" />
<input type="text" name="sender" id="id_sender" /> <input type="text" name="sender" id="id_sender" />
<input type="checkbox" name="cc_myself" id="id_cc_myself" /> <input type="checkbox" name="cc_myself" id="id_cc_myself" />
The field-specific output honors the form object's ``auto_id`` setting:: The field-specific output honors the form object's ``auto_id`` setting::
@ -624,26 +617,31 @@ The field-specific output honors the form object's ``auto_id`` setting::
>>> print f['message'] >>> print f['message']
<input type="text" name="message" id="id_message" /> <input type="text" name="message" id="id_message" />
For a field's list of errors, access the field's ``errors`` attribute. This For a field's list of errors, access the field's ``errors`` attribute.
is a list-like object that is displayed as an HTML ``<ul class="errorlist">``
when printed::
>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} .. attribute:: BoundField.errors
>>> f = ContactForm(data, auto_id=False)
>>> print f['message']
<input type="text" name="message" />
>>> f['message'].errors
[u'This field is required.']
>>> print f['message'].errors
<ul class="errorlist"><li>This field is required.</li></ul>
>>> f['subject'].errors
[]
>>> print f['subject'].errors
>>> str(f['subject'].errors) A list-like object that is displayed as an HTML ``<ul class="errorlist">``
'' when printed::
.. versionadded:: 1.2 >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
>>> f = ContactForm(data, auto_id=False)
>>> print f['message']
<input type="text" name="message" />
>>> f['message'].errors
[u'This field is required.']
>>> print f['message'].errors
<ul class="errorlist"><li>This field is required.</li></ul>
>>> f['subject'].errors
[]
>>> print f['subject'].errors
>>> str(f['subject'].errors)
''
.. method:: BoundField.css_classes()
.. versionadded:: 1.2
When you use Django's rendering shortcuts, CSS classes are used to When you use Django's rendering shortcuts, CSS classes are used to
indicate required form fields or fields that contain errors. If you're indicate required form fields or fields that contain errors. If you're
@ -662,6 +660,21 @@ those classes as an argument::
>>> f['message'].css_classes('foo bar') >>> f['message'].css_classes('foo bar')
'foo bar required' 'foo bar required'
.. method:: BoundField.values()
.. versionadded:: 1.3
Use this method to render the raw value of this field as it would be rendered
by a ``Widget``::
>>> initial = {'subject': 'welcome'}
>>> unbound_form = ContactForm(initial=initial)
>>> bound_form = ContactForm(data, initial=initial)
>>> print unbound_form['subject'].value
welcome
>>> print bound_form['subject'].value
hi
.. _binding-uploaded-files: .. _binding-uploaded-files:
Binding uploaded files to a form Binding uploaded files to a form

View File

@ -1151,6 +1151,21 @@ class FormsTestCase(TestCase):
<option value="w">whiz</option> <option value="w">whiz</option>
</select></li>""") </select></li>""")
def test_boundfield_values(self):
# It's possible to get to the value which would be used for rendering
# the widget for a field by using the BoundField's value method.
class UserRegistration(Form):
username = CharField(max_length=10, initial='djangonaut')
password = CharField(widget=PasswordInput)
unbound = UserRegistration()
bound = UserRegistration({'password': 'foo'})
self.assertEqual(bound['username'].value(), None)
self.assertEqual(unbound['username'].value(), 'djangonaut')
self.assertEqual(bound['password'].value(), 'foo')
self.assertEqual(unbound['password'].value(), None)
def test_help_text(self): def test_help_text(self):
# You can specify descriptive text for a field by using the 'help_text' argument) # You can specify descriptive text for a field by using the 'help_text' argument)
class UserRegistration(Form): class UserRegistration(Form):