Index: django/test/client.py
===================================================================
--- django/test/client.py	(revision 4615)
+++ django/test/client.py	(working copy)
@@ -167,7 +167,7 @@
         if response.cookies:
             self.cookies.update(response.cookies)
 
-        if 'django.contrib.sessions' in settings.INSTALLED_APPS:
+        if 'django.contrib.sessions' in [app.path for app in settings.INSTALLED_APPS]:
             from django.contrib.sessions.middleware import SessionWrapper
             cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
             if cookie:
Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py	(revision 4615)
+++ django/db/models/base.py	(working copy)
@@ -8,7 +8,7 @@
 from django.db.models.options import Options, AdminOptions
 from django.db import connection, backend, transaction
 from django.db.models import signals
-from django.db.models.loading import register_models, get_model
+from django.db.models.loading import register_models, get_model, get_app_label
 from django.dispatch import dispatcher
 from django.utils.datastructures import SortedDict
 from django.utils.functional import curry
@@ -42,7 +42,8 @@
         if getattr(new_class._meta, 'app_label', None) is None:
             # Figure out the app_label by looking one level up.
             # For 'django.contrib.sites.models', this would be 'sites'.
-            new_class._meta.app_label = model_module.__name__.split('.')[-2]
+            new_class._meta.app_label = get_app_label(new_class)
+            #new_class._meta.app_label = model_module.__name__.split('.')[-2]
 
         # Bail out early if we have already created this class.
         m = get_model(new_class._meta.app_label, name, False)
Index: django/db/models/options.py
===================================================================
--- django/db/models/options.py	(revision 4615)
+++ django/db/models/options.py	(working copy)
@@ -36,7 +36,7 @@
 
     def contribute_to_class(self, cls, name):
         cls._meta = self
-        self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS
+        self.installed = re.sub('\.models$', '', cls.__module__) in [app.path for app in settings.INSTALLED_APPS]
         # First, construct the default values for these options.
         self.object_name = cls.__name__
         self.module_name = self.object_name.lower()
Index: django/db/models/loading.py
===================================================================
--- django/db/models/loading.py	(revision 4615)
+++ django/db/models/loading.py	(working copy)
@@ -1,6 +1,6 @@
 "Utilities for loading models and the modules that contain them."
 
-from django.conf import settings
+from django.conf import settings, directives
 from django.core.exceptions import ImproperlyConfigured
 import sys
 import os
@@ -24,20 +24,20 @@
     global _loaded
     if not _loaded:
         _loaded = True
-        for app_name in settings.INSTALLED_APPS:
+        for app in settings.INSTALLED_APPS:
             try:
-                load_app(app_name)
+                load_app(app.path)
             except Exception, e:
                 # Problem importing the app
-                _app_errors[app_name] = e
+                _app_errors[app.path] = e
     return _app_list
 
 def get_app(app_label, emptyOK=False):
     "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None."
     get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
-    for app_name in settings.INSTALLED_APPS:
-        if app_label == app_name.split('.')[-1]:
-            mod = load_app(app_name)
+    for app in settings.INSTALLED_APPS:
+        if app_label == app.app_label:
+            mod = load_app(app.path)
             if mod is None:
                 if emptyOK:
                     return None
@@ -61,18 +61,22 @@
     get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
     return _app_errors
 
-def get_models(app_mod=None):
+def get_models(app=None):
     """
-    Given a module containing models, returns a list of the models. Otherwise
-    returns a list of all installed models.
+    Given a app config directive, returns a list of the models in that app. 
+    Otherwise returns a list of all installed models.
     """
     app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
-    if app_mod:
-        return _app_models.get(app_mod.__name__.split('.')[-2], {}).values()
+    if app:
+        if isinstance(app, str):
+            print app
+            app = app_for_label(app)
+            print app
+        return _app_models.get(app.app_label, {}).values()
     else:
         model_list = []
-        for app_mod in app_list:
-            model_list.extend(get_models(app_mod))
+        for app in settings.INSTALLED_APPS:
+            model_list.extend(get_models(app))
         return model_list
 
 def get_model(app_label, model_name, seed_cache=True):
@@ -114,3 +118,27 @@
             if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
                 continue
         model_dict[model_name] = model
+
+def get_app_label(model):
+    model_module_path = model.__module__
+    model_module_path_list = model_module_path.split('.')
+    model_module_index = model_module_path_list.index('models')
+    app_module_path_list = model_module_path_list[:model_module_index]
+    app_module_path = '.'.join(app_module_path_list)    
+    for app in settings.INSTALLED_APPS:
+        if app_module_path == app.path:
+            return app.app_label
+    # app is most likely not installed, but give it an app label using the old method
+    return model.__module__.split('.')[-2]
+
+def app_for_path(path):
+    for app in settings.INSTALLED_APPS:
+        if path == app.path:
+            return app
+    # app is most likely not installed, but give it an app label using the old method
+    return directives.app(path.split('.')[-1])
+
+def app_for_label(app_label):
+    for app in settings.INSTALLED_APPS:
+        if app_label == app.app_label:
+            return app
Index: django/conf/__init__.py
===================================================================
--- django/conf/__init__.py	(revision 4615)
+++ django/conf/__init__.py	(working copy)
@@ -8,7 +8,8 @@
 
 import os
 import time     # Needed for Windows
-from django.conf import global_settings
+from django.conf import global_settings, directives
+from django.utils.datastructures import SortedDict
 
 ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
 
@@ -94,14 +95,19 @@
                 setattr(self, setting, setting_value)
 
         # Expand entries in INSTALLED_APPS like "django.contrib.*" to a list
-        # of all those apps.
+        # of all those apps. Also, convert strings into app directives.
         new_installed_apps = []
         for app in self.INSTALLED_APPS:
-            if app.endswith('.*'):
-                appdir = os.path.dirname(__import__(app[:-2], {}, {}, ['']).__file__)
-                for d in os.listdir(appdir):
-                    if d.isalpha() and os.path.isdir(os.path.join(appdir, d)):
-                        new_installed_apps.append('%s.%s' % (app[:-2], d))
+            if isinstance(app, str):
+                if app.endswith('.*'):
+                    appdir = os.path.dirname(__import__(app[:-2], {}, {}, ['']).__file__)
+                    for d in os.listdir(appdir):
+                        if d.isalpha() and os.path.isdir(os.path.join(appdir, d)):
+                            new_app = directives.app('%s.%s' % (app[:-2], d))
+                            new_installed_apps.append(new_app)
+                else:
+                    new_app = directives.app(app)
+                    new_installed_apps.append(new_app)
             else:
                 new_installed_apps.append(app)
         self.INSTALLED_APPS = new_installed_apps
Index: django/conf/directives.py
===================================================================
--- django/conf/directives.py	(revision 0)
+++ django/conf/directives.py	(revision 0)
@@ -0,0 +1,14 @@
+class app(object):
+    """Configuration directive for specifying an app."""
+    def __init__(self, path, app_label=None, verbose_name=None):
+        self.path = path
+        # if name isn't specified, get the last part of the python dotted path
+        self.app_label = app_label or path.split('.')[-1]
+        self.verbose_name = verbose_name or self.app_label
+
+class backend(object):
+    """Configuration directive for specifying an authentication backend."""
+    def __init__(self, path, name=None):
+        self.path = path
+        # if name isn't specified, get the last part of the python dotted path
+        self.name = name or path.split('.')[-1]
Index: django/core/management.py
===================================================================
--- django/core/management.py	(revision 4615)
+++ django/core/management.py	(working copy)
@@ -56,10 +56,7 @@
 def _get_installed_models(table_list):
     "Gets a set of all models that are installed, given a list of existing tables"
     from django.db import models
-    all_models = []
-    for app in models.get_apps():
-        for model in models.get_models(app):
-            all_models.append(model)
+    all_models = models.get_models()
     return set([m for m in all_models if m._meta.db_table in table_list])
 
 def _get_table_list():
@@ -363,11 +360,12 @@
 
 def get_sql_initial_data(app):
     "Returns a list of the initial INSERT SQL statements for the given app."
-    from django.db.models import get_models
+    from django.db import models
     output = []
 
-    app_models = get_models(app)
-    app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
+    app_models = models.get_models(app)
+    app_module = models.get_app(app.app_label)
+    app_dir = os.path.normpath(os.path.join(os.path.dirname(app_module.__file__), 'sql'))
 
     for model in app_models:
         output.extend(get_sql_initial_data_for_model(model))
@@ -450,9 +448,9 @@
 
     # Import the 'management' module within each installed app, to register
     # dispatcher events.
-    for app_name in settings.INSTALLED_APPS:
+    for app in settings.INSTALLED_APPS:
         try:
-            __import__(app_name + '.management', {}, {}, [''])
+            __import__(app.path + '.management', {}, {}, [''])
         except ImportError:
             pass
 
@@ -469,8 +467,8 @@
     created_models = set()
     pending_references = {}
 
-    for app in models.get_apps():
-        app_name = app.__name__.split('.')[-2]
+    for app in settings.INSTALLED_APPS:
+        app_name = app.path
         model_list = models.get_models(app)
         for model in model_list:
             # Create the model's database table, if it doesn't already exist.
@@ -503,11 +501,12 @@
 
     # Send the post_syncdb signal, so individual apps can do whatever they need
     # to do at this point.
-    for app in models.get_apps():
-        app_name = app.__name__.split('.')[-2]
+    for app in settings.INSTALLED_APPS:
+        app_name = app.path
+        app_module = models.get_app(app.app_label)
         if verbosity >= 2:
             print "Running post-sync handlers for application", app_name
-        dispatcher.send(signal=signals.post_syncdb, sender=app,
+        dispatcher.send(signal=signals.post_syncdb, sender=app_module,
             app=app, created_models=created_models,
             verbosity=verbosity, interactive=interactive)
 
@@ -530,8 +529,8 @@
                         transaction.commit_unless_managed()
 
     # Install SQL indicies for all newly created models
-    for app in models.get_apps():
-        app_name = app.__name__.split('.')[-2]
+    for app in settings.INSTALLED_APPS:
+        app_name = app.path
         for model in models.get_models(app):
             if model in created_models:
                 index_sql = get_sql_indexes_for_model(model)
@@ -1402,21 +1401,22 @@
         action_mapping[action](args[1:])
     else:
         from django.db import models
+        from django.conf import settings
         validate(silent_success=True)
         try:
-            mod_list = [models.get_app(app_label) for app_label in args[1:]]
+            app_list = [app for app in settings.INSTALLED_APPS if app.app_label in args[1:]]
         except ImportError, e:
             sys.stderr.write(style.ERROR("Error: %s. Are you sure your INSTALLED_APPS setting is correct?\n" % e))
             sys.exit(1)
-        if not mod_list:
+        if not app_list:
             parser.print_usage_and_exit()
         if action not in NO_SQL_TRANSACTION:
             print style.SQL_KEYWORD("BEGIN;")
-        for mod in mod_list:
+        for app in app_list:
             if action == 'reset':
-                output = action_mapping[action](mod, options.interactive)
+                output = action_mapping[action](app, options.interactive)
             else:
-                output = action_mapping[action](mod)
+                output = action_mapping[action](app)
             if output:
                 print '\n'.join(output)
         if action not in NO_SQL_TRANSACTION:
Index: django/templatetags/__init__.py
===================================================================
--- django/templatetags/__init__.py	(revision 4615)
+++ django/templatetags/__init__.py	(working copy)
@@ -1,7 +1,7 @@
 from django.conf import settings
 
-for a in settings.INSTALLED_APPS:
+for app in settings.INSTALLED_APPS:
     try:
-        __path__.extend(__import__(a + '.templatetags', {}, {}, ['']).__path__)
+        __path__.extend(__import__(app.path + '.templatetags', {}, {}, ['']).__path__)
     except ImportError:
         pass
Index: django/views/i18n.py
===================================================================
--- django/views/i18n.py	(revision 4615)
+++ django/views/i18n.py	(working copy)
@@ -104,7 +104,7 @@
         packages = ['django.conf']
     if type(packages) in (str, unicode):
         packages = packages.split('+')
-    packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS]
+    packages = [p for p in packages if p == 'django.conf' or p in [app.path for app in settings.INSTALLED_APPS]]
     default_locale = to_locale(settings.LANGUAGE_CODE)
     locale = to_locale(get_language())
     t = {}
Index: django/contrib/admin/templatetags/adminapplist.py
===================================================================
--- django/contrib/admin/templatetags/adminapplist.py	(revision 4615)
+++ django/contrib/admin/templatetags/adminapplist.py	(working copy)
@@ -1,5 +1,6 @@
 from django import template
 from django.db.models import get_models
+from django.conf import settings
 
 register = template.Library()
 
@@ -13,12 +14,12 @@
         app_list = []
         user = context['user']
 
-        for app in models.get_apps():
+        for app in settings.INSTALLED_APPS:
             # Determine the app_label.
             app_models = get_models(app)
             if not app_models:
                 continue
-            app_label = app_models[0]._meta.app_label
+            app_label = app.app_label
 
             has_module_perms = user.has_module_perms(app_label)
 
@@ -49,7 +50,7 @@
                     model_list = [x for key, x in decorated]
 
                     app_list.append({
-                        'name': app_label.title(),
+                        'name': app.verbose_name.title(),
                         'has_module_perms': has_module_perms,
                         'models': model_list,
                     })
Index: django/utils/translation/trans_real.py
===================================================================
--- django/utils/translation/trans_real.py	(revision 4615)
+++ django/utils/translation/trans_real.py	(working copy)
@@ -161,14 +161,15 @@
         if projectpath and os.path.isdir(projectpath):
             res = _merge(projectpath)
 
-        for appname in settings.INSTALLED_APPS:
+        for app in settings.INSTALLED_APPS:
+            appname = app.path
             p = appname.rfind('.')
             if p >= 0:
-                app = getattr(__import__(appname[:p], {}, {}, [appname[p+1:]]), appname[p+1:])
+                app_module = getattr(__import__(appname[:p], {}, {}, [appname[p+1:]]), appname[p+1:])
             else:
-                app = __import__(appname, {}, {}, [])
+                app_module = __import__(appname, {}, {}, [])
 
-            apppath = os.path.join(os.path.dirname(app.__file__), 'locale')
+            apppath = os.path.join(os.path.dirname(app_module.__file__), 'locale')
 
             if os.path.isdir(apppath):
                 res = _merge(apppath)
Index: django/template/loaders/app_directories.py
===================================================================
--- django/template/loaders/app_directories.py	(revision 4615)
+++ django/template/loaders/app_directories.py	(working copy)
@@ -8,18 +8,18 @@
 # At compile time, cache the directories to search.
 app_template_dirs = []
 for app in settings.INSTALLED_APPS:
-    i = app.rfind('.')
+    i = app.path.rfind('.')
     if i == -1:
-        m, a = app, None
+        m, a = app.path, None
     else:
-        m, a = app[:i], app[i+1:]
+        m, a = app.path[:i], app.path[i+1:]
     try:
         if a is None:
             mod = __import__(m, {}, {}, [])
         else:
             mod = getattr(__import__(m, {}, {}, [a]), a)
     except ImportError, e:
-        raise ImproperlyConfigured, 'ImportError %s: %s' % (app, e.args[0])
+        raise ImproperlyConfigured, 'ImportError %s: %s' % (app.path, e.args[0])
     template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates')
     if os.path.isdir(template_dir):
         app_template_dirs.append(template_dir)
Index: django/template/loaders/eggs.py
===================================================================
--- django/template/loaders/eggs.py	(revision 4615)
+++ django/template/loaders/eggs.py	(working copy)
@@ -18,7 +18,7 @@
         pkg_name = 'templates/' + template_name
         for app in settings.INSTALLED_APPS:
             try:
-                return (resource_string(app, pkg_name), 'egg:%s:%s ' % (app, pkg_name))
+                return (resource_string(app.path, pkg_name), 'egg:%s:%s ' % (app.path, pkg_name))
             except:
                 pass
     raise TemplateDoesNotExist, template_name
Index: tests/runtests.py
===================================================================
--- tests/runtests.py	(revision 4615)
+++ tests/runtests.py	(working copy)
@@ -2,6 +2,7 @@
 
 import os, sys, traceback
 import unittest
+from django.conf import directives
 
 MODEL_TESTS_DIR_NAME = 'modeltests'
 REGRESSION_TESTS_DIR_NAME = 'regressiontests'
@@ -12,14 +13,14 @@
 REGRESSION_TEST_DIR = os.path.join(os.path.dirname(__file__), REGRESSION_TESTS_DIR_NAME)
 
 ALWAYS_INSTALLED_APPS = [
-    'django.contrib.contenttypes',
-    'django.contrib.auth',
-    'django.contrib.sites',
-    'django.contrib.flatpages',
-    'django.contrib.redirects',
-    'django.contrib.sessions',
-    'django.contrib.comments',
-    'django.contrib.admin',
+    directives.app('django.contrib.contenttypes'),
+    directives.app('django.contrib.auth'),
+    directives.app('django.contrib.sites'),
+    directives.app('django.contrib.flatpages'),
+    directives.app('django.contrib.redirects'),
+    directives.app('django.contrib.sessions'),
+    directives.app('django.contrib.comments'),
+    directives.app('django.contrib.admin'),
 ]
 
 def get_test_models():
@@ -48,16 +49,19 @@
 
     def runTest(self):
         from django.core import management
-        from django.db.models.loading import load_app
+        from django.db.models.loading import load_app, app_for_path
         from cStringIO import StringIO
 
         try:
             module = load_app(self.model_label)
+            app = app_for_path(self.model_label)
         except Exception, e:
+            print self.model_label
+            print e
             self.fail('Unable to load invalid model module')
 
         s = StringIO()
-        count = management.get_validation_errors(s, module)
+        count = management.get_validation_errors(s, app)
         s.seek(0)
         error_log = s.read()
         actual = error_log.split('\n')
@@ -108,8 +112,9 @@
             if not tests_to_run or model_name in tests_to_run:
                 if verbosity >= 1:
                     print "Importing model %s" % model_name
+                app = directives.app(model_label)
+                settings.INSTALLED_APPS.append(app)
                 mod = load_app(model_label)
-                settings.INSTALLED_APPS.append(model_label)
                 test_models.append(mod)
         except Exception, e:
             sys.stderr.write("Error while importing %s:" % model_name + ''.join(traceback.format_exception(*sys.exc_info())[1:]))
