Index: docs/ref/models/fields.txt
===================================================================
--- docs/ref/models/fields.txt	(revision 15803)
+++ docs/ref/models/fields.txt	(working copy)
@@ -999,6 +999,22 @@
       DELETE`` constraint to the database field (perhaps using
       :ref:`initial sql<initial-sql>`).
 
+.. versionadded:: 1.4
+
+.. attribute:: Model.choices_for_FOO()
+
+    It is possible to limit choices with respect to ``self``. Creat a method called 
+    ``choices_for_FOO``, where ``FOO`` is the name of the field. The method needs
+    to return a QuerySet::
+
+        class MyModel(models.Model):
+            user = models.ForeignKey(User)
+            
+            def choices_for_user(self):
+                # Make sure only active and currently associated users are in choices.
+                return self.__class__.objects.exclude(is_active=False)|
+                       self.__class__.objects.filter(id=self.user)
+
 .. _ref-manytomany:
 
 ``ManyToManyField``
Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py	(revision 15803)
+++ django/db/models/base.py	(working copy)
@@ -353,6 +353,15 @@
             else:
                 setattr(self, field.attname, val)
 
+        for field in self._meta.fields:
+            # Set the model field choices function on the field
+            # Refs #2445
+            if field.rel is None:
+                continue
+            choice_func = getattr(self, 'choices_for_%s' % field.name, None)
+            if callable(choice_func):
+                field.queryset = choice_func
+
         if kwargs:
             for prop in kwargs.keys():
                 try:
Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py	(revision 15803)
+++ django/db/models/fields/__init__.py	(working copy)
@@ -362,11 +362,10 @@
         first_choice = include_blank and blank_choice or []
         if self.choices:
             return first_choice + list(self.choices)
-        rel_model = self.rel.to
         if hasattr(self.rel, 'get_related_field'):
-            lst = [(getattr(x, self.rel.get_related_field().attname), smart_unicode(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
+            lst = [(getattr(x, self.rel.get_related_field().attname), smart_unicode(x)) for x in self.queryset]
         else:
-            lst = [(x._get_pk_val(), smart_unicode(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
+            lst = [(x._get_pk_val(), smart_unicode(x)) for x in self.queryset]
         return first_choice + lst
 
     def get_choices_default(self):
@@ -447,6 +446,16 @@
         "Returns the value of this field in the given model instance."
         return getattr(obj, self.attname)
 
+    def _get_queryset(self):
+        if hasattr(self, '_queryset'):
+            return self._queryset()
+        return self.rel.to._default_manager.complex_filter(self.rel.limit_choices_to)
+
+    def _set_queryset(self, qs):
+        self._queryset = qs
+
+    queryset = property(_get_queryset, _set_queryset)
+
 class AutoField(Field):
     description = _("Integer")
 
Index: django/db/models/fields/related.py
===================================================================
--- django/db/models/fields/related.py	(revision 15803)
+++ django/db/models/fields/related.py	(working copy)
@@ -847,10 +847,7 @@
             return
 
         using = router.db_for_read(model_instance.__class__, instance=model_instance)
-        qs = self.rel.to._default_manager.using(using).filter(
-                **{self.rel.field_name: value}
-             )
-        qs = qs.complex_filter(self.rel.limit_choices_to)
+        qs = self.queryset.using(using).filter(**{self.rel.field_name: value})
         if not qs.exists():
             raise exceptions.ValidationError(self.error_messages['invalid'] % {
                 'model': self.rel.to._meta.verbose_name, 'pk': value})
@@ -910,7 +907,7 @@
         db = kwargs.pop('using', None)
         defaults = {
             'form_class': forms.ModelChoiceField,
-            'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to),
+            'queryset': self.queryset.using(db),
             'to_field_name': self.rel.field_name,
         }
         defaults.update(kwargs)
Index: tests/modeltests/choices/tests.py
===================================================================
--- tests/modeltests/choices/tests.py	(revision 15803)
+++ tests/modeltests/choices/tests.py	(working copy)
@@ -1,3 +1,4 @@
+from django.db.models.query import QuerySet
 from django.test import TestCase
 
 from models import Person
@@ -21,3 +22,10 @@
         a.gender = 'U'
         self.assertEqual(a.get_gender_display(), 'U')
 
+    def test_callable(self):
+        for name, gender, parent in (('Adrian', 'M', None), ('Simon', 'M', 1), ('Karen', 'F', 1), ('Brian', 'F', 2)):
+            p = Person.objects.create(name=name, gender=gender, parent_id=parent)
+        
+        parent = p._meta.get_field('parent')
+        self.assertIsInstance(parent.queryset, QuerySet)
+        self.assertNotIn(p, parent.queryset)
Index: tests/modeltests/choices/models.py
===================================================================
--- tests/modeltests/choices/models.py	(revision 15803)
+++ tests/modeltests/choices/models.py	(working copy)
@@ -19,6 +19,10 @@
 class Person(models.Model):
     name = models.CharField(max_length=20)
     gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
+    parent = models.ForeignKey('self', blank=True, null=True, related_name='child')
 
     def __unicode__(self):
         return self.name
+
+    def choices_for_parent(self):
+        return self.__class__.objects.exclude(id=self.id)
