1
0
mirror of https://github.com/django/django.git synced 2025-10-24 22:26:08 +00:00

Fixed #7975 -- Callable defaults in inline model formsets now work correctly. Based on patch from msaelices. Thanks for your hard work msaelices.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@8816 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Brian Rosner
2008-09-01 21:28:32 +00:00
parent ca7db155aa
commit 7c7ad041b3
6 changed files with 149 additions and 22 deletions

View File

@@ -28,7 +28,7 @@ from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode, smart_str
from util import ErrorList, ValidationError
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput, TimeInput
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput, TimeInput, SplitHiddenDateTimeWidget
from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile
__all__ = (
@@ -59,7 +59,7 @@ class Field(object):
creation_counter = 0
def __init__(self, required=True, widget=None, label=None, initial=None,
help_text=None, error_messages=None):
help_text=None, error_messages=None, show_hidden_initial=False):
# required -- Boolean that specifies whether the field is required.
# True by default.
# widget -- A Widget class, or instance of a Widget class, that should
@@ -73,9 +73,12 @@ class Field(object):
# initial -- A value to use in this Field's initial display. This value
# is *not* used as a fallback if data isn't given.
# help_text -- An optional string to use as "help text" for this Field.
# show_hidden_initial -- Boolean that specifies if it is needed to render a
# hidden widget with initial value after widget.
if label is not None:
label = smart_unicode(label)
self.required, self.label, self.initial = required, label, initial
self.show_hidden_initial = show_hidden_initial
if help_text is None:
self.help_text = u''
else:
@@ -840,6 +843,7 @@ class FilePathField(ChoiceField):
self.widget.choices = self.choices
class SplitDateTimeField(MultiValueField):
hidden_widget = SplitHiddenDateTimeWidget
default_error_messages = {
'invalid_date': _(u'Enter a valid date.'),
'invalid_time': _(u'Enter a valid time.'),

View File

@@ -128,6 +128,12 @@ class BaseForm(StrAndUnicode):
"""
return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name
def add_initial_prefix(self, field_name):
"""
Add a 'initial' prefix for checking dynamic initial values
"""
return u'initial-%s' % self.add_prefix(field_name)
def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row):
"Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
@@ -245,7 +251,7 @@ class BaseForm(StrAndUnicode):
Returns True if data differs from initial.
"""
return bool(self.changed_data)
def _get_changed_data(self):
if self._changed_data is None:
self._changed_data = []
@@ -258,7 +264,13 @@ class BaseForm(StrAndUnicode):
for name, field in self.fields.items():
prefixed_name = self.add_prefix(name)
data_value = field.widget.value_from_datadict(self.data, self.files, prefixed_name)
initial_value = self.initial.get(name, field.initial)
if not field.show_hidden_initial:
initial_value = self.initial.get(name, field.initial)
else:
initial_prefixed_name = self.add_initial_prefix(name)
hidden_widget = field.hidden_widget()
initial_value = hidden_widget.value_from_datadict(
self.data, self.files, initial_prefixed_name)
if field.widget._has_changed(initial_value, data_value):
self._changed_data.append(name)
return self._changed_data
@@ -300,6 +312,7 @@ class BoundField(StrAndUnicode):
self.field = field
self.name = name
self.html_name = form.add_prefix(name)
self.html_initial_name = form.add_initial_prefix(name)
if self.field.label is None:
self.label = pretty_name(name)
else:
@@ -308,6 +321,8 @@ class BoundField(StrAndUnicode):
def __unicode__(self):
"""Renders this field as an HTML widget."""
if self.field.show_hidden_initial:
return self.as_widget() + self.as_hidden(only_initial=True)
return self.as_widget()
def _errors(self):
@@ -318,7 +333,7 @@ class BoundField(StrAndUnicode):
return self.form.errors.get(self.name, self.form.error_class())
errors = property(_errors)
def as_widget(self, widget=None, attrs=None):
def as_widget(self, widget=None, attrs=None, only_initial=False):
"""
Renders the field by rendering the passed widget, adding any HTML
attributes passed as attrs. If no widget is specified, then the
@@ -330,29 +345,33 @@ class BoundField(StrAndUnicode):
auto_id = self.auto_id
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
attrs['id'] = auto_id
if not self.form.is_bound:
if not self.form.is_bound or only_initial:
data = self.form.initial.get(self.name, self.field.initial)
if callable(data):
data = data()
else:
data = self.data
return widget.render(self.html_name, data, attrs=attrs)
def as_text(self, attrs=None):
if not only_initial:
name = self.html_name
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 <input type="text">.
"""
return self.as_widget(TextInput(), attrs)
return self.as_widget(TextInput(), attrs, **kwargs)
def as_textarea(self, attrs=None):
def as_textarea(self, attrs=None, **kwargs):
"Returns a string of HTML for representing this as a <textarea>."
return self.as_widget(Textarea(), attrs)
return self.as_widget(Textarea(), attrs, **kwargs)
def as_hidden(self, attrs=None):
def as_hidden(self, attrs=None, **kwargs):
"""
Returns a string of HTML for representing this as an <input type="hidden">.
"""
return self.as_widget(self.field.hidden_widget(), attrs)
return self.as_widget(self.field.hidden_widget(), attrs, **kwargs)
def _data(self):
"""

View File

@@ -25,7 +25,8 @@ __all__ = (
'HiddenInput', 'MultipleHiddenInput',
'FileInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput',
'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
'CheckboxSelectMultiple', 'MultiWidget',
'SplitDateTimeWidget',
)
MEDIA_TYPES = ('css','js')
@@ -617,7 +618,8 @@ class MultiWidget(Widget):
if initial is None:
initial = [u'' for x in range(0, len(data))]
else:
initial = self.decompress(initial)
if not isinstance(initial, list):
initial = self.decompress(initial)
for widget, initial, data in zip(self.widgets, initial, data):
if widget._has_changed(initial, data):
return True
@@ -662,3 +664,11 @@ class SplitDateTimeWidget(MultiWidget):
return [value.date(), value.time().replace(microsecond=0)]
return [None, None]
class SplitHiddenDateTimeWidget(SplitDateTimeWidget):
"""
A Widget that splits datetime input into two <input type="hidden"> inputs.
"""
def __init__(self, attrs=None):
widgets = (HiddenInput(attrs=attrs), HiddenInput(attrs=attrs))
super(SplitDateTimeWidget, self).__init__(widgets, attrs)