diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 4b8beb4341..7e56542024 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -231,7 +231,7 @@ class Field(object):
def get_default(self):
"Returns the default value for this field."
- if self.default is not NOT_PROVIDED:
+ if self.has_default():
if callable(self.default):
return self.default()
return force_unicode(self.default, strings_only=True)
@@ -306,7 +306,8 @@ class Field(object):
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
if self.has_default():
defaults['initial'] = self.get_default()
-
+ if callable(self.default):
+ defaults['show_hidden_initial'] = True
if self.choices:
# Fields with choices get special treatment.
include_blank = self.blank or not (self.has_default() or 'initial' in kwargs)
@@ -314,9 +315,7 @@ class Field(object):
defaults['coerce'] = self.to_python
if self.null:
defaults['empty_value'] = None
-
form_class = forms.TypedChoiceField
-
# Many of the subclass-specific formfield arguments (min_value,
# max_value) don't apply for choice fields, so be sure to only pass
# the values that TypedChoiceField will understand.
@@ -325,7 +324,6 @@ class Field(object):
'widget', 'label', 'initial', 'help_text',
'error_messages'):
del kwargs[k]
-
defaults.update(kwargs)
return form_class(**defaults)
diff --git a/django/forms/fields.py b/django/forms/fields.py
index e267498808..b20beb939f 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -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.'),
diff --git a/django/forms/forms.py b/django/forms/forms.py
index 7d1254c5ea..2d4f4462d0 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -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 .
"""
- 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