diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 60dcf72..5432ef4 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -327,6 +327,21 @@ class ManagementUtility(object):
             prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]]
             options = filter(lambda (x, v): x not in prev_opts, options)
 
+            if hasattr(subcommand_cls, 'complete'):
+                complete = subcommand_cls.complete()
+                if isinstance(complete, list):
+                    options += [(k, 0) for k in complete]
+                elif isinstance(complete, dict):
+                    to_add = complete[str(cword-2)]
+                    if to_add == 'COMMAND_NAME':
+                        print ' '.join(filter(lambda x: x.startswith(curr), subcommands))
+                    elif to_add == 'APP_NAME':
+                        from django.conf import settings
+                        options += [(a.split('.')[-1], 0) for a in settings.INSTALLED_APPS]
+                    else:
+                        options += to_add
+
+
             # filter options by current input
             options = [(k, v) for k, v in options if k.startswith(curr)]
             for option in options:
diff --git a/tests/regressiontests/bash_completion/__init__.py b/tests/regressiontests/bash_completion/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/bash_completion/management/__init__.py b/tests/regressiontests/bash_completion/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/bash_completion/management/commands/__init__.py b/tests/regressiontests/bash_completion/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/bash_completion/management/commands/dict_command.py b/tests/regressiontests/bash_completion/management/commands/dict_command.py
new file mode 100644
index 0000000..d7f0979
--- /dev/null
+++ b/tests/regressiontests/bash_completion/management/commands/dict_command.py
@@ -0,0 +1,20 @@
+import sys, os
+from optparse import OptionParser, make_option
+
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+    option_list = BaseCommand.option_list + (
+        make_option("--list", action="store_true", dest="list",
+                    help="Print all options"),
+    )
+
+    def complete(self):
+        return {
+            '0': [('awesome', None), ('sweet', None)],
+            '1': 'COMMAND_NAME',
+            '2': 'APP_NAME',
+        }
+
+    def handle(self, *args, **options):
+        pass
diff --git a/tests/regressiontests/bash_completion/management/commands/test_command.py b/tests/regressiontests/bash_completion/management/commands/test_command.py
new file mode 100644
index 0000000..2b9ec0f
--- /dev/null
+++ b/tests/regressiontests/bash_completion/management/commands/test_command.py
@@ -0,0 +1,16 @@
+import sys, os
+from optparse import OptionParser, make_option
+
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+    option_list = BaseCommand.option_list + (
+        make_option("--list", action="store_true", dest="list",
+                    help="Print all options"),
+    )
+
+    def complete(self):
+        return ['awesome', 'sweet']
+
+    def handle(self, *args, **options):
+        pass
diff --git a/tests/regressiontests/bash_completion/models.py b/tests/regressiontests/bash_completion/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/bash_completion/tests.py b/tests/regressiontests/bash_completion/tests.py
new file mode 100644
index 0000000..e751bee
--- /dev/null
+++ b/tests/regressiontests/bash_completion/tests.py
@@ -0,0 +1,90 @@
+"""
+A series of tests to establish that the command-line bash completion works.
+"""
+import os
+import unittest
+import sys
+import StringIO
+
+from django.core.management import ManagementUtility
+
+class BashCompletionTests(unittest.TestCase):
+    """
+    Testing the Python level bash completion code.
+    This requires settings up the environment like if we got passed data
+    from bash.
+    """
+
+    def setUp(self):
+        os.environ['DJANGO_AUTO_COMPLETE'] = '1'
+        self.output = StringIO.StringIO()
+        self.old_stdout = sys.stdout
+        sys.stdout = self.output
+
+    def tearDown(self):
+        sys.stdout = self.old_stdout
+
+    def _user_input(self, input_str):
+        os.environ['COMP_WORDS'] = input_str
+        os.environ['COMP_CWORD'] = str(len(input_str.split()) - 1)
+        sys.argv = input_str.split(' ')
+
+    def _run_autocomplete(self):
+        util = ManagementUtility(argv=sys.argv)
+        try:
+            util.autocomplete()
+        except SystemExit:
+            pass
+        return self.output.getvalue().strip().split('\n')
+
+    def test_django_admin_py(self):
+        self._user_input('django-admin.py sqlall --v')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['--verbosity='])
+
+    def test_manage_py(self):
+        self._user_input('manage.py sqlall --v')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['--verbosity='])
+
+    def test_custom_command(self):
+        self._user_input('django-admin.py test_command --l')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['--list'])
+
+    def test_subcommands(self):
+        self._user_input('django-admin.py sql')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['sqlinitialdata sqlclear sqlreset sqlsequencereset sql sqlall sqlflush sqlcustom sqlindexes'])
+
+    def test_help(self):
+        #Help should return nothing since it takes no args.
+        self._user_input('django-admin.py help --')
+        output = self._run_autocomplete()
+        self.assertEqual(output, [''])
+
+    def test_runfcgi(self):
+        #runfcgi has its own special options
+        self._user_input('django-admin.py runfcgi h')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['host='])
+
+    def test_app_completion(self):
+        self._user_input('django-admin.py sqlall a')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['auth', 'admin'])
+
+    def test_dict_return_list(self):
+        self._user_input('django-admin.py dict_command a')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['awesome'])
+
+    def test_dict_return_commands(self):
+        self._user_input('django-admin.py dict_command awesome sqlal')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['sqlall'])
+
+    def test_dict_return_apps(self):
+        self._user_input('django-admin.py dict_command awesome sqlall a')
+        output = self._run_autocomplete()
+        self.assertEqual(output, ['auth', 'admin'])
