summaryrefslogtreecommitdiff
path: root/django/forms
diff options
context:
space:
mode:
authorArthur Koziel <arthur@arthurkoziel.com>2010-09-13 00:04:27 +0000
committerArthur Koziel <arthur@arthurkoziel.com>2010-09-13 00:04:27 +0000
commitdd49269c7db008b2567f50cb03c4d3d9b321daa1 (patch)
tree326dd25bb045ac016cda7966b43cbdfe1f67d699 /django/forms
parentc9b188c4ec939abbe48dae5a371276742e64b6b8 (diff)
downloaddjango-soc2010/app-loading.tar.gz
[soc2010/app-loading] merged trunkarchive/soc2010/app-loadingsoc2010/app-loading
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/app-loading@13818 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/forms')
-rw-r--r--django/forms/fields.py5
-rw-r--r--django/forms/forms.py20
-rw-r--r--django/forms/formsets.py14
-rw-r--r--django/forms/models.py58
-rw-r--r--django/forms/widgets.py45
5 files changed, 91 insertions, 51 deletions
diff --git a/django/forms/fields.py b/django/forms/fields.py
index 0bae4ba157..de14a5c8a8 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -127,6 +127,9 @@ class Field(object):
self.validators = self.default_validators + validators
+ def prepare_value(self, value):
+ return value
+
def to_python(self, value):
return value
@@ -396,6 +399,8 @@ class DateTimeField(Field):
# components: date and time.
if len(value) != 2:
raise ValidationError(self.error_messages['invalid'])
+ if value[0] in validators.EMPTY_VALUES and value[1] in validators.EMPTY_VALUES:
+ return None
value = '%s %s' % tuple(value)
for format in self.input_formats or formats.get_format('DATETIME_INPUT_FORMATS'):
try:
diff --git a/django/forms/forms.py b/django/forms/forms.py
index b3718efa9a..7b2bc66fc7 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -18,10 +18,10 @@ __all__ = ('BaseForm', 'Form')
NON_FIELD_ERRORS = '__all__'
def pretty_name(name):
- """Converts 'first_name' to 'First name'"""
- if not name:
- return u''
- return name.replace('_', ' ').capitalize()
+ """Converts 'first_name' to 'First name'"""
+ if not name:
+ return u''
+ return name.replace('_', ' ').capitalize()
def get_declared_fields(bases, attrs, with_base_fields=True):
"""
@@ -35,7 +35,7 @@ def get_declared_fields(bases, attrs, with_base_fields=True):
Also integrates any additional media definitions
"""
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
- fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
+ fields.sort(key=lambda x: x[1].creation_counter)
# If this class is subclassing another Form, add that Form's fields.
# Note that we loop over the bases in *reverse*. This is necessary in
@@ -213,7 +213,7 @@ class BaseForm(StrAndUnicode):
normal_row = u'<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>',
error_row = u'<tr><td colspan="2">%s</td></tr>',
row_ender = u'</td></tr>',
- help_text_html = u'<br />%s',
+ help_text_html = u'<br /><span class="helptext">%s</span>',
errors_on_separate_row = False)
def as_ul(self):
@@ -222,7 +222,7 @@ class BaseForm(StrAndUnicode):
normal_row = u'<li%(html_class_attr)s>%(errors)s%(label)s %(field)s%(help_text)s</li>',
error_row = u'<li>%s</li>',
row_ender = '</li>',
- help_text_html = u' %s',
+ help_text_html = u' <span class="helptext">%s</span>',
errors_on_separate_row = False)
def as_p(self):
@@ -231,7 +231,7 @@ class BaseForm(StrAndUnicode):
normal_row = u'<p%(html_class_attr)s>%(label)s %(field)s%(help_text)s</p>',
error_row = u'%s',
row_ender = '</p>',
- help_text_html = u' %s',
+ help_text_html = u' <span class="helptext">%s</span>',
errors_on_separate_row = True)
def non_field_errors(self):
@@ -423,6 +423,7 @@ class BoundField(StrAndUnicode):
"""
if not widget:
widget = self.field.widget
+
attrs = attrs or {}
auto_id = self.auto_id
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
@@ -430,6 +431,7 @@ class BoundField(StrAndUnicode):
attrs['id'] = auto_id
else:
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):
@@ -439,6 +441,8 @@ class BoundField(StrAndUnicode):
data = self.form.initial.get(self.name, self.field.initial)
else:
data = self.data
+ data = self.field.prepare_value(data)
+
if not only_initial:
name = self.html_name
else:
diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index 3804f2b3c1..508950eee9 100644
--- a/django/forms/formsets.py
+++ b/django/forms/formsets.py
@@ -199,14 +199,12 @@ class BaseFormSet(StrAndUnicode):
# A sort function to order things numerically ascending, but
# None should be sorted below anything else. Allowing None as
# a comparison value makes it so we can leave ordering fields
- # blamk.
- def compare_ordering_values(x, y):
- if x[1] is None:
- return 1
- if y[1] is None:
- return -1
- return x[1] - y[1]
- self._ordering.sort(compare_ordering_values)
+ # blank.
+ def compare_ordering_key(k):
+ if k[1] is None:
+ return (1, 0) # +infinity, larger than any number
+ return (0, k[1])
+ self._ordering.sort(key=compare_ordering_key)
# Return a list of form.cleaned_data dicts in the order spcified by
# the form data.
return [self.forms[i[0]] for i in self._ordering]
diff --git a/django/forms/models.py b/django/forms/models.py
index 8accd61f30..cf465ad30c 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -9,7 +9,8 @@ from django.utils.datastructures import SortedDict
from django.utils.text import get_text_list, capfirst
from django.utils.translation import ugettext_lazy as _, ugettext
-from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
+from django.core.exceptions import ValidationError, NON_FIELD_ERRORS, \
+ FieldError
from django.core.validators import EMPTY_VALUES
from util import ErrorList
from forms import BaseForm, get_declared_fields
@@ -150,7 +151,7 @@ def model_to_dict(instance, fields=None, exclude=None):
data[f.name] = f.value_from_object(instance)
return data
-def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
+def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_callback=None):
"""
Returns a ``SortedDict`` containing form fields for the given model.
@@ -175,7 +176,14 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_c
kwargs = {'widget': widgets[f.name]}
else:
kwargs = {}
- formfield = formfield_callback(f, **kwargs)
+
+ if formfield_callback is None:
+ formfield = f.formfield(**kwargs)
+ elif not callable(formfield_callback):
+ raise TypeError('formfield_callback must be a function or callable')
+ else:
+ formfield = formfield_callback(f, **kwargs)
+
if formfield:
field_list.append((f.name, formfield))
else:
@@ -198,8 +206,7 @@ class ModelFormOptions(object):
class ModelFormMetaclass(type):
def __new__(cls, name, bases, attrs):
- formfield_callback = attrs.pop('formfield_callback',
- lambda f, **kwargs: f.formfield(**kwargs))
+ formfield_callback = attrs.pop('formfield_callback', None)
try:
parents = [b for b in bases if issubclass(b, ModelForm)]
except NameError:
@@ -218,6 +225,15 @@ class ModelFormMetaclass(type):
# If a model is defined, extract form fields from it.
fields = fields_for_model(opts.model, opts.fields,
opts.exclude, opts.widgets, formfield_callback)
+ # make sure opts.fields doesn't specify an invalid field
+ none_model_fields = [k for k, v in fields.iteritems() if not v]
+ missing_fields = set(none_model_fields) - \
+ set(declared_fields.keys())
+ if missing_fields:
+ message = 'Unknown field(s) (%s) specified for %s'
+ message = message % (', '.join(missing_fields),
+ opts.model.__name__)
+ raise FieldError(message)
# Override default model fields with any custom declared ones
# (plus, include all the other declared fields).
fields.update(declared_fields)
@@ -376,7 +392,7 @@ class ModelForm(BaseModelForm):
__metaclass__ = ModelFormMetaclass
def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
- formfield_callback=lambda f: f.formfield()):
+ formfield_callback=None):
# Create the inner Meta class. FIXME: ideally, we should be able to
# construct a ModelForm without creating and passing in a temporary
# inner class.
@@ -658,7 +674,7 @@ class BaseModelFormSet(BaseFormSet):
form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)
super(BaseModelFormSet, self).add_fields(form, index)
-def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
+def modelformset_factory(model, form=ModelForm, formfield_callback=None,
formset=BaseModelFormSet,
extra=1, can_delete=False, can_order=False,
max_num=None, fields=None, exclude=None):
@@ -813,7 +829,7 @@ def inlineformset_factory(parent_model, model, form=ModelForm,
formset=BaseInlineFormSet, fk_name=None,
fields=None, exclude=None,
extra=3, can_order=False, can_delete=True, max_num=None,
- formfield_callback=lambda f: f.formfield()):
+ formfield_callback=None):
"""
Returns an ``InlineFormSet`` for the given kwargs.
@@ -906,12 +922,7 @@ class ModelChoiceIterator(object):
return len(self.queryset)
def choice(self, obj):
- if self.field.to_field_name:
- key = obj.serializable_value(self.field.to_field_name)
- else:
- key = obj.pk
- return (key, self.field.label_from_instance(obj))
-
+ return (self.field.prepare_value(obj), self.field.label_from_instance(obj))
class ModelChoiceField(ChoiceField):
"""A ChoiceField whose choices are a model QuerySet."""
@@ -971,8 +982,8 @@ class ModelChoiceField(ChoiceField):
return self._choices
# Otherwise, execute the QuerySet in self.queryset to determine the
- # choices dynamically. Return a fresh QuerySetIterator that has not been
- # consumed. Note that we're instantiating a new QuerySetIterator *each*
+ # choices dynamically. Return a fresh ModelChoiceIterator that has not been
+ # consumed. Note that we're instantiating a new ModelChoiceIterator *each*
# time _get_choices() is called (and, thus, each time self.choices is
# accessed) so that we can ensure the QuerySet has not been consumed. This
# construct might look complicated but it allows for lazy evaluation of
@@ -981,13 +992,21 @@ class ModelChoiceField(ChoiceField):
choices = property(_get_choices, ChoiceField._set_choices)
+ def prepare_value(self, value):
+ if hasattr(value, '_meta'):
+ if self.to_field_name:
+ return value.serializable_value(self.to_field_name)
+ else:
+ return value.pk
+ return super(ModelChoiceField, self).prepare_value(value)
+
def to_python(self, value):
if value in EMPTY_VALUES:
return None
try:
key = self.to_field_name or 'pk'
value = self.queryset.get(**{key: value})
- except self.queryset.model.DoesNotExist:
+ except (ValueError, self.queryset.model.DoesNotExist):
raise ValidationError(self.error_messages['invalid_choice'])
return value
@@ -1030,3 +1049,8 @@ class ModelMultipleChoiceField(ModelChoiceField):
if force_unicode(val) not in pks:
raise ValidationError(self.error_messages['invalid_choice'] % val)
return qs
+
+ def prepare_value(self, value):
+ if hasattr(value, '__iter__'):
+ return [super(ModelMultipleChoiceField, self).prepare_value(v) for v in value]
+ return super(ModelMultipleChoiceField, self).prepare_value(value)
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index e3799c69ad..2e16c35d8b 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -229,7 +229,7 @@ class TextInput(Input):
class PasswordInput(Input):
input_type = 'password'
- def __init__(self, attrs=None, render_value=True):
+ def __init__(self, attrs=None, render_value=False):
super(PasswordInput, self).__init__(attrs)
self.render_value = render_value
@@ -308,9 +308,13 @@ class DateInput(Input):
super(DateInput, self).__init__(attrs)
if format:
self.format = format
+ self.manual_format = True
+ else:
+ self.format = formats.get_format('DATE_INPUT_FORMATS')[0]
+ self.manual_format = False
def _format_value(self, value):
- if self.is_localized:
+ if self.is_localized and not self.manual_format:
return formats.localize_input(value)
elif hasattr(value, 'strftime'):
value = datetime_safe.new_date(value)
@@ -336,9 +340,13 @@ class DateTimeInput(Input):
super(DateTimeInput, self).__init__(attrs)
if format:
self.format = format
+ self.manual_format = True
+ else:
+ self.format = formats.get_format('DATETIME_INPUT_FORMATS')[0]
+ self.manual_format = False
def _format_value(self, value):
- if self.is_localized:
+ if self.is_localized and not self.manual_format:
return formats.localize_input(value)
elif hasattr(value, 'strftime'):
value = datetime_safe.new_datetime(value)
@@ -364,9 +372,13 @@ class TimeInput(Input):
super(TimeInput, self).__init__(attrs)
if format:
self.format = format
+ self.manual_format = True
+ else:
+ self.format = formats.get_format('TIME_INPUT_FORMATS')[0]
+ self.manual_format = False
def _format_value(self, value):
- if self.is_localized:
+ if self.is_localized and not self.manual_format:
return formats.localize_input(value)
elif hasattr(value, 'strftime'):
return value.strftime(self.format)
@@ -438,13 +450,14 @@ class Select(Widget):
output.append(u'</select>')
return mark_safe(u'\n'.join(output))
+ def render_option(self, selected_choices, option_value, option_label):
+ option_value = force_unicode(option_value)
+ selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
+ return u'<option value="%s"%s>%s</option>' % (
+ escape(option_value), selected_html,
+ conditional_escape(force_unicode(option_label)))
+
def render_options(self, choices, selected_choices):
- def render_option(option_value, option_label):
- option_value = force_unicode(option_value)
- selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
- return u'<option value="%s"%s>%s</option>' % (
- escape(option_value), selected_html,
- conditional_escape(force_unicode(option_label)))
# Normalize to strings.
selected_choices = set([force_unicode(v) for v in selected_choices])
output = []
@@ -452,10 +465,10 @@ class Select(Widget):
if isinstance(option_label, (list, tuple)):
output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
for option in option_label:
- output.append(render_option(*option))
+ output.append(self.render_option(selected_choices, *option))
output.append(u'</optgroup>')
else:
- output.append(render_option(option_value, option_label))
+ output.append(self.render_option(selected_choices, option_value, option_label))
return u'\n'.join(output)
class NullBooleanSelect(Select):
@@ -751,12 +764,8 @@ class SplitDateTimeWidget(MultiWidget):
time_format = TimeInput.format
def __init__(self, attrs=None, date_format=None, time_format=None):
- if date_format:
- self.date_format = date_format
- if time_format:
- self.time_format = time_format
- widgets = (DateInput(attrs=attrs, format=self.date_format),
- TimeInput(attrs=attrs, format=self.time_format))
+ widgets = (DateInput(attrs=attrs, format=date_format),
+ TimeInput(attrs=attrs, format=time_format))
super(SplitDateTimeWidget, self).__init__(widgets, attrs)
def decompress(self, value):