Index: django/utils/autoreload.py
===================================================================
--- django/utils/autoreload.py	(revision 788)
+++ django/utils/autoreload.py	(working copy)
@@ -37,6 +37,7 @@
     mtimes = {}
     while RUN_RELOADER:
         for filename in filter(lambda v: v, map(lambda m: getattr(m, "__file__", None), sys.modules.values())) + reloadFiles:
+            if not os.path.exists(filename): continue # file might be in an egg, so it can't be reloaded
             if filename.endswith(".pyc"):
                 filename = filename[:-1]
             mtime = os.stat(filename).st_mtime
Index: django/conf/global_settings.py
===================================================================
--- django/conf/global_settings.py	(revision 788)
+++ django/conf/global_settings.py	(working copy)
@@ -60,6 +60,15 @@
 # Extension on all templates.
 TEMPLATE_FILE_EXTENSION = '.html'
 
+# Callables which know how to import template sources from various
+# sources; the expected interface is callable(name, [dirs]), where dirs
+# is a list of directories to search instead of TEMPLATE_DIRS.
+TEMPLATE_SOURCE_LOADERS = (
+    'django.core.template_file.load_template_source',
+    'django.core.template_eggs.load_template_source',
+)
+
+
 # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
 # trailing slash.
 # Examples: "http://foo.com/media/", "/media/".
Index: django/core/template_loader.py
===================================================================
--- django/core/template_loader.py	(revision 788)
+++ django/core/template_loader.py	(working copy)
@@ -1,7 +1,31 @@
 "Wrapper for loading templates from storage of some sort (e.g. files or db)"
 import template
-from template_file import load_template_source
 
+from django.conf.settings import TEMPLATE_SOURCE_LOADERS
+from django.core import exceptions
+
+template_source_loaders = []
+for path in TEMPLATE_SOURCE_LOADERS:
+    i = path.rfind('.')
+    module, attr = path[:i], path[i+1:]
+    try:
+        mod = __import__(module, globals(), locals(), [attr])
+    except ImportError, e:
+        raise exceptions.ImproperlyConfigured, 'Error importing template_source_loader %s: "%s"' % (module, e)
+    try:
+        template_source_loaders.append(getattr(mod, attr))
+    except AttributeError:
+        raise exceptions.ImproperlyConfigured, 'Module "%s" does not define a "%s" callable template_source_loader' % (module, attr)
+
+def load_template_source(name, dirs=None):
+    for loader in template_source_loaders:
+        try:
+            return loader(name, dirs)
+        except template.TemplateDoesNotExist:
+            pass
+    raise template.TemplateDoesNotExist, name
+
+
 class ExtendsError(Exception):
     pass
 
@@ -24,7 +48,7 @@
     Loads the given template_name and renders it with the given dictionary as
     context. The template_name may be a string to load a single template using
     get_template, or it may be a tuple to use select_template to find one of
-    the templates in the list.  Returns a string. 
+    the templates in the list.  Returns a string.
     """
     dictionary = dictionary or {}
     if isinstance(template_name, (list, tuple)):
Index: django/core/servers/basehttp.py
===================================================================
--- django/core/servers/basehttp.py	(revision 788)
+++ django/core/servers/basehttp.py	(working copy)
@@ -616,14 +616,33 @@
 
         # Find the admin file and serve it up, if it exists and is readable.
         relative_url = environ['PATH_INFO'][len(self.media_url):]
-        file_path = os.path.join(self.media_dir, relative_url)
-        if not os.path.exists(file_path):
+
+        # Nasty hack to see if we're running in an egg
+        # We can't just use resource_* as we do when setting up, because
+        # the user might have set the media_dir to be something outside
+        # the egg, and so resource_* won't find it. So, check for .egg in media_dir,
+        # and if it's there then use resource_* to get the resources.
+        if self.media_dir.find('.egg') == -1:
+          MEDIA_PATH_IS_REAL = True
+          file_path = os.path.join(self.media_dir, relative_url)
+          path_exists = os.path.exists(file_path)
+        else:
+          from pkg_resources import resource_exists, resource_stream
+          import django
+          MEDIA_PATH_IS_REAL = False
+          file_path = self.media_dir[len(django.__path__[0]):] + '/' + relative_url
+          path_exists = resource_exists('django',file_path)
+
+        if not path_exists:
             status = '404 NOT FOUND'
             headers = {'Content-type': 'text/plain'}
             output = ['Page not found: %s' % file_path]
         else:
             try:
-                fp = open(file_path, 'rb')
+                if MEDIA_PATH_IS_REAL:
+                  fp = open(file_path, 'rb')
+                else:
+                  fp = resource_stream('django',file_path)
             except IOError:
                 status = '401 UNAUTHORIZED'
                 headers = {'Content-type': 'text/plain'}
Index: django/core/management.py
===================================================================
--- django/core/management.py	(revision 788)
+++ django/core/management.py	(working copy)
@@ -3,6 +3,11 @@
 
 import django
 import os, re, sys
+try:
+  from pkg_resources import resource_listdir, resource_isdir, resource_stream
+  OK_IN_EGG = True
+except:
+  OK_IN_EGG = False
 
 MODULE_TEMPLATE = '''    {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%}
     <tr>
@@ -353,8 +358,17 @@
     except OSError, e:
         sys.stderr.write("Error: %s\n" % e)
         sys.exit(1)
-    template_dir = PROJECT_TEMPLATE_DIR % app_or_project
-    for d, subdirs, files in os.walk(template_dir):
+    if OK_IN_EGG:
+      # Use setuptools.resource_* to get the resources, which should work whether
+      # django is installed as a directory or as an egg
+      template_dir = (PROJECT_TEMPLATE_DIR % app_or_project)[len(django.__path__[0])+1:]
+      print template_dir
+      walklist = _walk_pkgresources_helper(template_dir)
+    else:
+      # Use django.__path__, which is the installation directory
+      template_dir = PROJECT_TEMPLATE_DIR % app_or_project
+      walklist = os.walk(template_dir)
+    for d, subdirs, files in walklist:
         relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name)
         if relative_dir:
             os.mkdir(os.path.join(top_dir, relative_dir))
@@ -364,12 +378,39 @@
         for f in files:
             if f.endswith('.pyc'):
                 continue
-            fp_old = open(os.path.join(d, f), 'r')
+            if OK_IN_EGG:
+              fp_old = resource_stream('django',d + '/' + f)
+            else:
+              fp_old = open(os.path.join(d, f), 'r')
             fp_new = open(os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name)), 'w')
             fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
             fp_old.close()
             fp_new.close()
 
+def _walk_pkgresources_helper(top, topdown=True, onerror=None):
+    """An equivalent to os.walk but using the setuptools resource_* APIs, in order
+       to allow walking over directories inside egg files."""
+    try:
+        names = resource_listdir('django',top)
+    except:
+        # Should handle an error callback here, but we don't.
+        return
+    dirs, nondirs = [], []
+    for name in names:
+        if resource_isdir('django',top + '/' + name): # note, / separate, not os.path.join
+            dirs.append(name)
+        else:
+            nondirs.append(name)
+
+    if topdown:
+        yield top, dirs, nondirs
+    for name in dirs:
+        path = top + '/' + name
+        for x in _walk_pkgresources_helper(path, topdown, onerror):
+            yield x
+    if not topdown:
+        yield top, dirs, nondirs
+
 def startproject(project_name, directory):
     "Creates a Django project for the given project_name in the given directory."
     from random import choice
@@ -379,6 +420,14 @@
     admin_settings_file = os.path.join(directory, project_name, 'settings/admin.py')
     settings_contents = open(admin_settings_file, 'r').read()
     fp = open(admin_settings_file, 'w')
+    # Nasty hack to see if we're running in an egg
+    # If we're running as an egg, then the admin template path must be
+    # a path that's *relative* to the Django install dir. If we're not,
+    # then it must be an *absolute* path. So if .egg is in django.__path__[0],
+    # make the path relative.
+    admin_template_dir_to_use = ADMIN_TEMPLATE_DIR
+    if admin_template_dir_to_use.find('.egg') == -1:
+        admin_template_dir_to_use = admin_template_dir_to_use[len(django.__path__[0]):]
     settings_contents = re.sub(r'(?s)\b(TEMPLATE_DIRS\s*=\s*\()(.*?)\)', "\\1\n    r%r,\\2)" % ADMIN_TEMPLATE_DIR, settings_contents)
     fp.write(settings_contents)
     fp.close()
