diff --git a/django/forms/fields.py b/django/forms/fields.py
index 621d380..d7b6ebb 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -743,6 +743,15 @@ class NullBooleanField(BooleanField):
         return initial != data
 
 
+class CallableChoiceIterator(object):
+    def __init__(self, callme, field):
+        self.callme = callme
+        self.field = field
+
+    def __iter__(self):
+        for e in self.callme(self.field):
+            yield e
+
 class ChoiceField(Field):
     widget = Select
     default_error_messages = {
@@ -757,7 +766,7 @@ class ChoiceField(Field):
 
     def __deepcopy__(self, memo):
         result = super(ChoiceField, self).__deepcopy__(memo)
-        result._choices = copy.deepcopy(self._choices, memo)
+        result._set_choices(copy.deepcopy(self._choices, memo))
         return result
 
     def _get_choices(self):
@@ -765,9 +774,14 @@ class ChoiceField(Field):
 
     def _set_choices(self, value):
         # Setting choices also sets the choices on the widget.
-        # choices can be any iterable, but we call list() on it because
-        # it will be consumed more than once.
-        self._choices = self.widget.choices = list(value)
+        if callable(value):
+            value = CallableChoiceIterator(value, self)
+        else:
+            # choices can be any iterable, but we call list() on it because
+            # it will be consumed more than once.
+            value = list(value)
+
+        self._choices = self.widget.choices = value
 
     choices = property(_get_choices, _set_choices)
 
diff --git a/django/forms/models.py b/django/forms/models.py
index d545a07..006d8b1 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -7,7 +7,7 @@ from __future__ import absolute_import, unicode_literals
 
 from django.core.exceptions import ValidationError, NON_FIELD_ERRORS, FieldError
 from django.core.validators import EMPTY_VALUES
-from django.forms.fields import Field, ChoiceField
+from django.forms.fields import Field, ChoiceField, CallableChoiceIterator
 from django.forms.forms import BaseForm, get_declared_fields
 from django.forms.formsets import BaseFormSet, formset_factory
 from django.forms.util import ErrorList
@@ -899,28 +899,31 @@ class InlineForeignKeyField(Field):
 
 class ModelChoiceIterator(object):
     def __init__(self, field):
-        self.field = field
-        self.queryset = field.queryset
+        self._delegate = CallableChoiceIterator(queryset_callable, field)
 
     def __iter__(self):
-        if self.field.empty_label is not None:
-            yield ("", self.field.empty_label)
-        if self.field.cache_choices:
-            if self.field.choice_cache is None:
-                self.field.choice_cache = [
-                    self.choice(obj) for obj in self.queryset.all()
-                ]
-            for choice in self.field.choice_cache:
-                yield choice
-        else:
-            for obj in self.queryset.all():
-                yield self.choice(obj)
+        return self._delegate.__iter__()
 
     def __len__(self):
-        return len(self.queryset)
-
-    def choice(self, obj):
-        return (self.field.prepare_value(obj), self.field.label_from_instance(obj))
+        return len(self.field.queryset)
+
+
+def queryset_callable(field):
+    def choice(obj):
+        return (field.prepare_value(obj), field.label_from_instance(obj))
+
+    if field.empty_label is not None:
+        yield ("", field.empty_label)
+    if field.cache_choices:
+        if field.choice_cache is None:
+            field.choice_cache = [
+                choice(obj) for obj in field.queryset.all()
+            ]
+        for choice in field.choice_cache:
+            yield choice
+    else:
+        for obj in field.queryset.all():
+            yield choice(obj)
 
 class ModelChoiceField(ChoiceField):
     """A ChoiceField whose choices are a model QuerySet."""
diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py
index 3fe2cd2..bdce0ba 100644
--- a/tests/regressiontests/forms/tests/fields.py
+++ b/tests/regressiontests/forms/tests/fields.py
@@ -49,7 +49,6 @@ def fix_os_paths(x):
     else:
         return x
 
-
 class FieldsTests(SimpleTestCase):
 
     def assertWidgetRendersTo(self, field, to):
@@ -893,6 +892,27 @@ class FieldsTests(SimpleTestCase):
         f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False, empty_value=None)
         self.assertEqual(None, f.clean(''))
 
+    def test_choicefield_callable(self):
+        choices = lambda field: [('J', 'John'), ('P', 'Paul')]
+        f = ChoiceField(choices=choices)
+        self.assertEqual(u'J', f.clean('J'))
+      
+    def test_choicefield_callable_may_evaluate_to_different_values(self):
+        choices = []
+        def choices_as_callable(field):
+            return choices
+
+        class ChoiceFieldForm(Form):
+            choicefield = ChoiceField(choices=choices_as_callable)
+
+        choices = [('J', 'John'), ('P', 'Paul')]
+        form = ChoiceFieldForm()
+        self.assertTrue("John" in form.as_p())
+
+        choices = [('M', 'Marie'),]
+        form = ChoiceFieldForm()
+        self.assertTrue("Marie" in form.as_p())
+
     # NullBooleanField ############################################################
 
     def test_nullbooleanfield_1(self):
