diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index f2723a18c7..679b37cfca 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -948,7 +948,10 @@ class ManyToManyField(RelatedField, Field):
# If initial is passed in, it's a list of related objects, but the
# MultipleChoiceField takes a list of IDs.
if defaults.get('initial') is not None:
- defaults['initial'] = [i._get_pk_val() for i in defaults['initial']]
+ initial = defaults['initial']
+ if callable(initial):
+ initial = initial()
+ defaults['initial'] = [i._get_pk_val() for i in initial]
return super(ManyToManyField, self).formfield(**defaults)
def db_type(self):
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 16b50145d7..c5795b7e56 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -613,6 +613,30 @@ Add some categories and test the many-to-many form output.
Hold down "Control", or "Command" on a Mac, to select more than one.
+Initial values can be provided for model forms
+>>> f = TestArticleForm(auto_id=False, initial={'headline': 'Your headline here', 'categories': ['1','2']})
+>>> print f.as_ul()
+
Headline:
+
Slug:
+
Pub date:
+
Writer:
+
Article:
+
Status:
+
Categories: Hold down "Control", or "Command" on a Mac, to select more than one.
+
>>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}, instance=new_art)
>>> new_art = f.save()
diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py
index 642cd203ca..bf9623fe77 100644
--- a/tests/regressiontests/forms/forms.py
+++ b/tests/regressiontests/forms/forms.py
@@ -1146,37 +1146,63 @@ possible to specify callable data.
>>> class UserRegistration(Form):
... username = CharField(max_length=10)
... password = CharField(widget=PasswordInput)
+... options = MultipleChoiceField(choices=[('f','foo'),('b','bar'),('w','whiz')])
We need to define functions that get called later.
>>> def initial_django():
... return 'django'
>>> def initial_stephane():
... return 'stephane'
+>>> def initial_options():
+... return ['f','b']
+>>> def initial_other_options():
+... return ['b','w']
+
Here, we're not submitting any data, so the initial value will be displayed.
->>> p = UserRegistration(initial={'username': initial_django}, auto_id=False)
+>>> p = UserRegistration(initial={'username': initial_django, 'options': initial_options}, auto_id=False)
>>> print p.as_ul()
Username:
Password:
+
Options:
The 'initial' parameter is meaningless if you pass data.
->>> p = UserRegistration({}, initial={'username': initial_django}, auto_id=False)
+>>> p = UserRegistration({}, initial={'username': initial_django, 'options': initial_options}, auto_id=False)
>>> print p.as_ul()
A callable 'initial' value is *not* used as a fallback if data is not provided.
In this example, we don't provide a value for 'username', and the form raises a
validation error rather than using the initial value for 'username'.
->>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django})
+>>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django, 'options': initial_options})
>>> p.errors['username']
[u'This field is required.']
>>> p.is_valid()
@@ -1187,14 +1213,26 @@ then the latter will get precedence.
>>> class UserRegistration(Form):
... username = CharField(max_length=10, initial=initial_django)
... password = CharField(widget=PasswordInput)
+... options = MultipleChoiceField(choices=[('f','foo'),('b','bar'),('w','whiz')], initial=initial_other_options)
+
>>> p = UserRegistration(auto_id=False)
>>> print p.as_ul()
Username:
Password:
->>> p = UserRegistration(initial={'username': initial_stephane}, auto_id=False)
+