--- a/django/core/management.py
+++ b/django/core/management.py
@@ -638,6 +638,162 @@ def startapp(app_name, directory):
 startapp.help_doc = "Creates a Django app directory structure for the given app name in the current directory."
 startapp.args = "[appname]"
 
+def createsuperuser(username=None, email=None, password=None):
+    "Creates a superuser account."
+    from django.core import validators
+    from django.contrib.auth.models import User
+    import getpass
+
+    try:
+        import pwd
+    except ImportError:
+        default_username = ''
+    else:
+        # Determine the current system user's username, to use as a default.
+        default_username = pwd.getpwuid(os.getuid())[0].replace(' ', '').lower()
+
+    # Determine whether the default username is taken, so we don't display
+    # it as an option.
+    if default_username:
+        try:
+            User.objects.get(username=default_username)
+        except User.DoesNotExist:
+            pass
+        else:
+            default_username = ''
+
+    try:
+        while 1:
+            if not username:
+                input_msg = 'Username'
+                if default_username:
+                    input_msg += ' (Leave blank to use %r)' % default_username
+                username = raw_input(input_msg + ': ')
+            if default_username and username == '':
+                username = default_username
+            if not username.isalnum():
+                sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
+                username = None
+            try:
+                User.objects.get(username=username)
+            except User.DoesNotExist:
+                break
+            else:
+                sys.stderr.write("Error: That username is already taken.\n")
+                username = None
+        while 1:
+            if not email:
+                email = raw_input('E-mail address: ')
+            try:
+                validators.isValidEmail(email, None)
+            except validators.ValidationError:
+                sys.stderr.write("Error: That e-mail address is invalid.\n")
+                email = None
+            else:
+                break
+        while 1:
+            if not password:
+                password = getpass.getpass()
+                password2 = getpass.getpass('Password (again): ')
+                if password != password2:
+                    sys.stderr.write("Error: Your passwords didn't match.\n")
+                    password = None
+                    continue
+            if password.strip() == '':
+                sys.stderr.write("Error: Blank passwords aren't allowed.\n")
+                password = None
+                continue
+            break
+    except KeyboardInterrupt:
+        sys.stderr.write("\nOperation cancelled.\n")
+        sys.exit(1)
+    u = User.objects.create_user(username, email, password)
+    u.is_staff = True
+    u.is_active = True
+    u.is_superuser = True
+    u.save()
+    print "User created successfully."
+createsuperuser.args = '[username] [email] [password] (Either all or none)'
+
+def _topological_sort(cursor, introspection_module, table_names):
+    """
+    sorts the table names in a way that there are no forward references.
+    At least it tries. 
+    generates the pairs for the ordered list of table names: ( table_name, forward_refs )
+    forward_refs is a set of table names that are referenced with a forward reference
+    that could not be avoided
+    """
+    # tables_in is a list [ (table_name, [ referenced_table_name ] ], excluding self references
+    tables_in = [ ( name, [ val[1] 
+                            for val in introspection_module.get_relations(cursor, name).values()
+                            if val[1] != name ])
+                  for name in table_names ]
+    #
+    # build the sorted list
+    tables_out_set = set()
+    # sort by number of references and lexically (to get a defined order that doesn't change from inspect to inspect)
+    tables_in.sort(lambda (name1,refs1),(name2,refs2): cmp(len(refs1),len(refs2)) or cmp(name1,name2))
+    # go through list until everything is handled
+    while tables_in != [ ]:
+        for (i, (table_name, refs)) in enumerate(tables_in):
+            for ref in refs:
+                if ref not in tables_out_set:
+                    # forward reference found, try next element
+                    break
+            else:
+                # bingo! take this element to the ordered tables
+                # and start processing the list with the first element
+                tables_out_set.add(table_name)
+                del tables_in[i]
+                yield (table_name, set())
+                break
+        else:
+            # There is no element without forward references in tables_in
+            # i.e. we have circular references
+            # strategy: find the table that is referenced most often
+            # and put it here. This will most probably break the cycle
+            # with only one trouble maker.
+            refcount = { }
+            referrers = { }
+            max_ref = 0
+            max_reffered = None
+            for (referrer_name, refs) in tables_in:
+                for ref in refs:
+                    if (not ref in tables_out_set 
+                        and not referrer_name in referrers.setdefault(ref,[ ])):
+                        referrers[ref].append(referrer_name)
+                        refcount[ref] = refcount.get(ref,0) + 1
+                        if refcount[ref] > max_ref:
+                            max_ref = refcount[ref]
+                            max_referred = ref
+            for (i,(table_name,refs)) in enumerate(tables_in):
+                if table_name == max_referred:
+                    candidate = i
+                    break
+            else:
+                # paranoia, cannot really happen
+                candidate = 0
+            # removing the references from the first entry will
+            # make sure that the first entry will be taken anyway
+            # during the next while loop run.
+            # possible improvement: reorder tables_in according to
+            #                       number of remaining unresolved references
+            bad_table_name = tables_in[candidate][0]
+            forward_references = [ x for x in tables_in[candidate][1] 
+                                   if x not in tables_out_set ]
+            print "# cyclic references detected at this point"
+            print "# %s contains these forward references: %s" % (
+                bad_table_name,
+                ", ".join(forward_references))
+            bad_referrers = referrers[bad_table_name]
+            bad_referrers.sort()
+            print "# and is referenced by %s" % ", ".join(bad_referrers)
+            tables_out_set.add(bad_table_name)
+            del tables_in[candidate]
+            yield (bad_table_name, set(forward_references))
+    return
+
+
 def inspectdb(db_name):
     "Generator that introspects the tables in the given database name and returns a Django model, one line at a time."
     from django.db import connection, get_introspection_module
@@ -663,12 +819,20 @@ def inspectdb(db_name):
     yield ''
     yield 'from django.db import models'
     yield ''
-    for table_name in introspection_module.get_table_list(cursor):
+    for (table_name, forward_referenced_tables) in (
+           _topological_sort(cursor, introspection_module,
+                             introspection_module.get_table_list(cursor))):
         yield 'class %s(models.Model):' % table2model(table_name)
         try:
             relations = introspection_module.get_relations(cursor, table_name)
         except NotImplementedError:
             relations = {}
+        # relation_count :: {other_table_name: ref_count}
+        # counts for each other table, how often it is referred by this table.
+        # (needed for the decision whether we need related_name attributes)
+        relation_count = {}
+        for (field_index, (field_index_other_table, other_table)) in relations.iteritems():
+            relation_count[other_table] = relation_count.setdefault(other_table,0) + 1
         try:
             indexes = introspection_module.get_indexes(cursor, table_name)
         except NotImplementedError:
@@ -683,14 +847,19 @@ def inspectdb(db_name):
                 att_name += '_field'
                 comment_notes.append('Field renamed because it was a Python reserved word.')
 
-            if relations.has_key(i):
-                rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
-                field_type = 'ForeignKey(%s' % rel_to
+            if (relations.has_key(i)
+                and relations[i][1] not in forward_referenced_tables):
+                rel_to = relations[i][1] == table_name and "'self'" or "%s" % table2model(relations[i][1])
+                field_type = "ForeignKey(%s" % rel_to
                 if att_name.endswith('_id'):
                     att_name = att_name[:-3]
                 else:
                     extra_params['db_column'] = att_name
+                if relation_count[relations[i][1]] > 1:
+                    extra_params['related_name'] = '%s_by_%s' % (table_name, att_name)
             else:
+                if relations.has_key(i):
+                    comment_notes.append('This is a forward foreign key reference to %s.' % table2model(relations[i][1]))
                 try:
                     field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]
                 except KeyError:
