diff --git a/AUTHORS b/AUTHORS
index 047ba91..8f7ed43 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -206,6 +206,7 @@ answer newbie questions, and generally made Django that much better:
     Scot Hacker <shacker@birdhouse.org>
     dAniel hAhler
     hambaloney
+    Chuck Harmston <chuck@chuckharmston.com>
     Brian Harring <ferringb@gmail.com>
     Brant Harris
     Ronny Haryanto <http://ronny.haryan.to/>
diff --git a/django/contrib/admin/media/css/widgets.css b/django/contrib/admin/media/css/widgets.css
index 620e082..b1c7768 100644
--- a/django/contrib/admin/media/css/widgets.css
+++ b/django/contrib/admin/media/css/widgets.css
@@ -5,6 +5,10 @@
     float: left;
 }
 
+.selector-single{
+	width: 282px !important;
+}
+
 .selector select {
     width: 270px;
     height: 17.2em;
diff --git a/django/contrib/admin/media/js/fkfilter.js b/django/contrib/admin/media/js/fkfilter.js
new file mode 100644
index 0000000..07bd84c
--- /dev/null
+++ b/django/contrib/admin/media/js/fkfilter.js
@@ -0,0 +1,79 @@
+(function($){
+	
+	$.fn.fk_filter = function(verbose_name) {
+		
+		if(verbose_name === 'undefined') var verbose_name = '';
+		
+		return this.each(function(){
+			
+			$(this).attr('size', 2); // Force a multi-row <select>
+			$(this).find('option[value=""]').remove(); // Remove the '-----'
+			
+			// Create the wrappers
+			var outerwrapper = $('<div />', {
+				'class': 'selector selector-single'
+			});
+			$(this).wrap(outerwrapper);
+			var innerwrapper = $('<div />', {
+				'class': 'selector-available'
+			});
+			$(this).wrap(innerwrapper);
+			
+			// Creates Header
+			var header = $('<h2 />', {
+				'text': interpolate(gettext('Available %s'), [verbose_name])
+			}).insertBefore(this);
+			
+			// Creates search bar
+			var searchbar = $('<p />', {
+				'html': '<img src="/media/img/admin/selector-search.gif"> <input type="text" id="' + $(this).attr('id') + '_input">',
+				'class': 'selector-filter'
+			}).insertBefore(this);
+			
+			var select = $(this);
+			var filter = $('#' + $(this).attr('id') + '_input');
+			
+			// Creates cache
+			var cache = [];
+			select.find('option').each(function(index, element){
+				cache.push({
+					'text': $(element).text(),
+					'value': $(element).val(),
+					'selected': $(element).attr('selected')
+				});
+			});
+			select.data('django-cache', cache);
+			
+			// Adjust cache on change
+			select.bind('change.fkfilter', function(evt){
+				var thisval = $(this).val();
+				var cache = select.data('django-cache');
+				
+				// for() used over $.each() for performance on long lists
+				for(var i = 0; i < cache.length; i++){
+					cache[i]['selected'] = (cache[i]['value'] == thisval);
+				}
+			});
+			
+			// Repopulate from cache on keyup
+			filter.bind('keyup.fkfilter', function(evt){
+				select.children().remove();
+				var regex = new RegExp(filter.val(), 'gi');
+				var cache = select.data('django-cache');
+				
+				// for() used over $.each() for performance on long lists
+				for(var i = 0; i < cache.length; i++){
+					if(cache[i]['text'].match(regex)){
+						$('<option />', {
+							'selected': cache[i]['selected'],
+							'value': cache[i]['value'],
+							'text': cache[i]['text']
+						}).appendTo(select);
+					}
+				}
+			});
+			
+		});
+	};
+	
+})(django.jQuery);
\ No newline at end of file
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 3b6e2b7..1a0e7a6 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -61,6 +61,7 @@ class BaseModelAdmin(object):
     exclude = None
     fieldsets = None
     form = forms.ModelForm
+    fk_filter = ()
     filter_vertical = ()
     filter_horizontal = ()
     radio_fields = {}
@@ -157,6 +158,9 @@ class BaseModelAdmin(object):
                 'class': get_ul_class(self.radio_fields[db_field.name]),
             })
             kwargs['empty_label'] = db_field.blank and _('None') or None
+        elif db_field.name in self.fk_filter:
+            kwargs['widget'] = widgets.FilteredSelectSingle(
+                db_field.verbose_name, (db_field.name in self.filter_vertical))
 
         return db_field.formfield(**kwargs)
 
@@ -1237,6 +1241,8 @@ class InlineModelAdmin(BaseModelAdmin):
             js.append('js/prepopulate.min.js')
         if self.filter_vertical or self.filter_horizontal:
             js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
+        if self.fk_filter:
+            js.append('js/fkfilter.js')
         return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
     media = property(_media)
 
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
index 134effc..72e4dcb 100644
--- a/django/contrib/admin/widgets.py
+++ b/django/contrib/admin/widgets.py
@@ -15,6 +15,38 @@ from django.utils.encoding import force_unicode
 from django.conf import settings
 from django.core.urlresolvers import reverse, NoReverseMatch
 
+
+class FilteredSelectSingle(forms.Select):
+    """
+    A Select with a JavaScript filter interface.
+    
+    Note that the resulting JavaScript assumes that the js18n catalog has been 
+    loaded in the page.
+    """
+    class Media:
+        js = (settings.ADMIN_MEDIA_PREFIX + "js/fkfilter.js",)
+
+    def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
+        self.verbose_name = verbose_name
+        self.is_stacked = is_stacked
+        super(FilteredSelectSingle, self).__init__(attrs, choices)
+
+    def render(self, name, value, attrs=None, choices=()):
+        if attrs is None: attrs = {}
+        attrs['class'] = 'selectfilter'
+        if self.is_stacked: attrs['class'] += 'stacked'
+        output = [super(FilteredSelectSingle, self).render(
+            name, value, attrs, choices)]
+        output.append((
+            '<script type="text/javascript">'
+            'django.jQuery(document).ready(function(){'
+            'django.jQuery("#id_%s").fk_filter("%s")'
+            '});'
+            '</script>'
+        ) % (name, self.verbose_name.replace('"', '\\"'),));
+        return mark_safe(u''.join(output))
+
+
 class FilteredSelectMultiple(forms.SelectMultiple):
     """
     A SelectMultiple with a JavaScript filter interface.
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 0550576..7c68806 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -247,11 +247,14 @@ Since the Author model only has three fields, ``name``, ``title``, and
 ``birth_date``, the forms resulting from the above declarations will contain
 exactly the same fields.
 
+.. attribute:: ModelAdmin.fk_filter
+
+Use a nifty unobtrusive JavaScript "filter" interface instead of the usability-challenged ``<select>`` in the admin form. The value is a list of ForeignKey fields that should be displayed as a filter interface. See ``filter_horizontal`` and ``filter_vertical`` to use the same filtering interface on a ManyToManyField.
+
 .. attribute:: ModelAdmin.filter_horizontal
 
-Use a nifty unobtrusive JavaScript "filter" interface instead of the
-usability-challenged ``<select multiple>`` in the admin form. The value is a
-list of fields that should be displayed as a horizontal filter interface. See
+Uses the same JavaScript "filter" interface as ``fk_filter``, replacing the usability-challenged ``<select multiple>`` in the admin form. The value is a
+list of ManyToMany fields that should be displayed as a horizontal filter interface. See
 ``filter_vertical`` to use a vertical interface.
 
 .. attribute:: ModelAdmin.filter_vertical
diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py
index 36ea416..297ea1c 100644
--- a/tests/regressiontests/modeladmin/models.py
+++ b/tests/regressiontests/modeladmin/models.py
@@ -516,6 +516,33 @@ ImproperlyConfigured: 'ValidationTestModelAdmin.filter_vertical[0]' must be a Ma
 ...     filter_vertical = ("users",)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 
+# fk_filter
+
+>>> class ValidationTestModelAdmin(ModelAdmin):
+...     fk_filter = 42
+>>> validate(ValidationTestModelAdmin, ValidationTestModel)
+Traceback (most recent call last):
+...
+ImproperlyConfigured: 'ValidationTestModelAdmin.filter_horizontal' must be a list or tuple.
+
+>>> class ValidationTestModelAdmin(ModelAdmin):
+...     fk_filter = ("non_existent_field",)
+>>> validate(ValidationTestModelAdmin, ValidationTestModel)
+Traceback (most recent call last):
+...
+ImproperlyConfigured: 'ValidationTestModelAdmin.fk_filter' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
+
+>>> class ValidationTestModelAdmin(ModelAdmin):
+...     fk_filter = ("name",)
+>>> validate(ValidationTestModelAdmin, ValidationTestModel)
+Traceback (most recent call last):
+...
+ImproperlyConfigured: 'ValidationTestModelAdmin.fk_filter[0]' must be a ForeignKey.
+
+>>> class ValidationTestModelAdmin(ModelAdmin):
+...     fk_filter = ("band",)
+>>> validate(ValidationTestModelAdmin, ValidationTestModel)
+
 # filter_horizontal
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
