summaryrefslogtreecommitdiff
path: root/django/forms
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2010-08-14 12:05:41 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2010-08-14 12:05:41 +0000
commitb3dc3a0106062bf28a28dc426885e7002a16a761 (patch)
tree0d87d0284a688cab74158738b8541838242ecdd7 /django/forms
parentd69cdc6d706db67a0ee118d9aaab82f9e7e5dcba (diff)
Fixed #13679, #13231, #7287 -- Ensured that models that have ForeignKeys/ManyToManyField can use a a callable default that returns a model instance/queryset. #13679 was a regression in behavior; the other two tickets are pleasant side effects. Thanks to 3point2 for the report.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@13577 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/forms')
-rw-r--r--django/forms/fields.py3
-rw-r--r--django/forms/forms.py12
-rw-r--r--django/forms/models.py24
-rw-r--r--django/forms/widgets.py17
4 files changed, 36 insertions, 20 deletions
diff --git a/django/forms/fields.py b/django/forms/fields.py
index 0bae4ba157..f6d9c4db54 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
diff --git a/django/forms/forms.py b/django/forms/forms.py
index dc0800b436..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):
"""
@@ -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/models.py b/django/forms/models.py
index 8accd61f30..a14a09f553 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -906,12 +906,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 +966,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,6 +976,14 @@ 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
@@ -1030,3 +1033,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 7a812ecc84..2e16c35d8b 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -450,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 = []
@@ -464,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):