Index: django/contrib/admin/filterspecs.py
===================================================================
--- django/contrib/admin/filterspecs.py	(revision 11627)
+++ django/contrib/admin/filterspecs.py	(working copy)
@@ -60,7 +60,9 @@
             self.lookup_title = f.verbose_name
         rel_name = f.rel.get_related_field().name
         self.lookup_kwarg = '%s__%s__exact' % (f.name, rel_name)
+        self.lookup_null_kwarg = '%s__isnull' % (f.name)
         self.lookup_val = request.GET.get(self.lookup_kwarg, None)
+        self.lookup_null = request.GET.get(self.lookup_null_kwarg, None)
         self.lookup_choices = f.get_choices(include_blank=False)
 
     def has_output(self):
@@ -70,13 +72,17 @@
         return self.lookup_title
 
     def choices(self, cl):
-        yield {'selected': self.lookup_val is None,
-               'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
+        yield {'selected': self.lookup_val is None and not self.lookup_null,
+               'query_string': cl.get_query_string({}, [self.lookup_kwarg, self.lookup_null_kwarg]),
                'display': _('All')}
         for pk_val, val in self.lookup_choices:
             yield {'selected': self.lookup_val == smart_unicode(pk_val),
-                   'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
+                   'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}, [self.lookup_null_kwarg]),
                    'display': val}
+        if self.field.null:
+            yield {'selected': self.lookup_null,
+                   'query_string': cl.get_query_string({self.lookup_null_kwarg: 'True'}, [self.lookup_kwarg]),
+                   'display': '(None)'}
 
 FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
 
@@ -162,18 +168,24 @@
     def __init__(self, f, request, params, model, model_admin):
         super(AllValuesFilterSpec, self).__init__(f, request, params, model, model_admin)
         self.lookup_val = request.GET.get(f.name, None)
+        self.lookup_null = request.GET.get(f.name + '__isnull', None)
         self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values(f.name)
 
     def title(self):
         return self.field.verbose_name
 
     def choices(self, cl):
-        yield {'selected': self.lookup_val is None,
-               'query_string': cl.get_query_string({}, [self.field.name]),
+        yield {'selected': self.lookup_val is None and not self.lookup_null,
+               'query_string': cl.get_query_string({}, [self.field.name, self.field.name + '__isnull']),
                'display': _('All')}
         for val in self.lookup_choices:
-            val = smart_unicode(val[self.field.name])
-            yield {'selected': self.lookup_val == val,
-                   'query_string': cl.get_query_string({self.field.name: val}),
-                   'display': val}
-FilterSpec.register(lambda f: True, AllValuesFilterSpec)
+            if val[self.field.name] is None:
+                yield {'selected': self.lookup_null,
+                       'query_string': cl.get_query_string({self.field.name + '__isnull': 'True'}, [self.field.name]),
+                       'display': '(None)'}
+            else:
+                val = smart_unicode(val[self.field.name])
+                yield {'selected': self.lookup_val == val,
+                       'query_string': cl.get_query_string({self.field.name: val}, [self.field.name + '__isnull']),
+                       'display': val}
+FilterSpec.register(lambda f: True, AllValuesFilterSpec)
