Index: django/newforms/models.py
===================================================================
--- django/newforms/models.py	(revision 7319)
+++ django/newforms/models.py	(working copy)
@@ -278,18 +278,17 @@
 # Fields #####################################################################
 
 class QuerySetIterator(object):
-    def __init__(self, queryset, empty_label, cache_choices):
-        self.queryset = queryset
-        self.empty_label = empty_label
-        self.cache_choices = cache_choices
+    def __init__(self, field):
+        self.field = field
+        self.queryset = field.queryset
 
     def __iter__(self):
-        if self.empty_label is not None:
-            yield (u"", self.empty_label)
+        if self.field.empty_label is not None:
+            yield (u"", self.field.empty_label)
         for obj in self.queryset:
-            yield (obj.pk, smart_unicode(obj))
+            yield (obj.pk, self.field.label_from_instance(obj))
         # Clear the QuerySet cache if required.
-        if not self.cache_choices:
+        if not self.field.cache_choices:
             self.queryset._result_cache = None
 
 class ModelChoiceField(ChoiceField):
@@ -321,6 +320,11 @@
 
     queryset = property(_get_queryset, _set_queryset)
 
+    # this method will be used to create object labels by the QuerySetIterator. 
+    # Override it to customize the label. 
+    def label_from_instance(self, obj):
+        return smart_unicode(obj)
+    
     def _get_choices(self):
         # If self._choices is set, then somebody must have manually set
         # the property self.choices. In this case, just return self._choices.
@@ -331,9 +335,9 @@
         # been consumed. Note that we're instantiating a new QuerySetIterator
         # *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.
-        return QuerySetIterator(self.queryset, self.empty_label,
-                                self.cache_choices)
+        # been consumed. This construct might look complicated but it allows 
+        # for lazy evaluation of the queryset.
+        return QuerySetIterator(self)
 
     def _set_choices(self, value):
         # This method is copied from ChoiceField._set_choices(). It's necessary
Index: tests/modeltests/model_forms/models.py
===================================================================
--- tests/modeltests/model_forms/models.py	(revision 7319)
+++ tests/modeltests/model_forms/models.py	(working copy)
@@ -645,7 +645,20 @@
 ...
 ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
 
+# check that we can safely iterate choices repeatedly
+>>> gen_one = list(f.choices)
+>>> gen_two = f.choices
+>>> gen_one[2]
+(2L, u"It's a test")
+>>> list(gen_two)
+[(u'', u'---------'), (1L, u'Entertainment'), (2L, u"It's a test"), (3L, u'Third')]
 
+# check that we can override the label_from_instance method to print custom labels (#4620)
+>>> f.queryset = Category.objects.all()
+>>> f.label_from_instance = lambda obj: "category " + str(obj)
+>>> list(f.choices)
+[(u'', u'---------'), (1L, 'category Entertainment'), (2L, "category It's a test"), (3L, 'category Third'), (4L, 'category Fourth')]
+
 # ModelMultipleChoiceField ####################################################
 
 >>> f = ModelMultipleChoiceField(Category.objects.all())
@@ -730,6 +743,10 @@
 ...
 ValidationError: [u'Select a valid choice. 4 is not one of the available choices.']
 
+>>> f.queryset = Category.objects.all()
+>>> f.label_from_instance = lambda obj: "multicategory " + str(obj)
+>>> list(f.choices)
+[(1L, 'multicategory Entertainment'), (2L, "multicategory It's a test"), (3L, 'multicategory Third'), (4L, 'multicategory Fourth')]
 
 # PhoneNumberField ############################################################
 
Index: docs/newforms.txt
===================================================================
--- docs/newforms.txt	(revision 7319)
+++ docs/newforms.txt	(working copy)
@@ -1517,13 +1517,18 @@
 ~~~~~~~~~~~~~~~~~~~~
 
 Allows the selection of a single model object, suitable for
-representing a foreign key.
+representing a foreign key. A ``ModelChoiceField`` will use the 
+``__unicode__()`` method of the model to represent them, but this 
+can be customized by overriding the ``label_from_instance`` method
+of the field itself (ie subclassing it). The method receives an object 
+as an argument and must return a string to represent it. 
 
 ``ModelMultipleChoiceField``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Allows the selection of one or more model objects, suitable for
-representing a many-to-many relation.
+representing a many-to-many relation. As with ``ModelChoiceField``, 
+you can use ``label_from_instance`` to customize the object labels.
 
 
 Creating custom fields
