diff --git a/django/contrib/auth/handlers/__init__.py b/django/contrib/auth/handlers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/django/contrib/auth/handlers/modpython.py b/django/contrib/auth/handlers/modpython.py
deleted file mode 100644
index de961fa..0000000
--- a/django/contrib/auth/handlers/modpython.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from mod_python import apache
-import os
-
-def authenhandler(req, **kwargs):
-    """
-    Authentication handler that checks against Django's auth database.
-    """
-
-    # mod_python fakes the environ, and thus doesn't process SetEnv.  This fixes
-    # that so that the following import works
-    os.environ.update(req.subprocess_env)
-
-    # apache 2.2 requires a call to req.get_basic_auth_pw() before 
-    # req.user and friends are available.
-    req.get_basic_auth_pw()
-
-    # check for PythonOptions
-    _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
-
-    options = req.get_options()
-    permission_name = options.get('DjangoPermissionName', None)
-    staff_only = _str_to_bool(options.get('DjangoRequireStaffStatus', "on"))
-    superuser_only = _str_to_bool(options.get('DjangoRequireSuperuserStatus', "off"))
-    settings_module = options.get('DJANGO_SETTINGS_MODULE', None)
-    if settings_module:
-        os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
-
-    from django.contrib.auth.models import User
-    from django import db
-    db.reset_queries()
-
-    # check that the username is valid
-    kwargs = {'username': req.user, 'is_active': True}
-    if staff_only:
-        kwargs['is_staff'] = True
-    if superuser_only:
-        kwargs['is_superuser'] = True
-    try:
-        try:
-            user = User.objects.get(**kwargs)
-        except User.DoesNotExist:
-            return apache.HTTP_UNAUTHORIZED
-    
-        # check the password and any permission given
-        if user.check_password(req.get_basic_auth_pw()):
-            if permission_name:
-                if user.has_perm(permission_name):
-                    return apache.OK
-                else:
-                    return apache.HTTP_UNAUTHORIZED
-            else:
-                return apache.OK
-        else:
-            return apache.HTTP_UNAUTHORIZED
-    finally:
-        db.connection.close()
diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py
index 9eac8ec..d8095d4 100644
--- a/django/core/cache/__init__.py
+++ b/django/core/cache/__init__.py
@@ -14,6 +14,8 @@ cache class.
 
 See docs/topics/cache.txt for information on the public API.
 """
+from urlparse import parse_qsl
+
 from django.conf import settings
 from django.core import signals
 from django.core.cache.backends.base import (
@@ -21,12 +23,6 @@ from django.core.cache.backends.base import (
 from django.core.exceptions import ImproperlyConfigured
 from django.utils import importlib
 
-try:
-    # The mod_python version is more efficient, so try importing it first.
-    from mod_python.util import parse_qsl
-except ImportError:
-    from urlparse import parse_qsl
-
 __all__ = [
     'get_cache', 'cache', 'DEFAULT_CACHE_ALIAS'
 ]
diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py
deleted file mode 100644
index fb23fb4..0000000
--- a/django/core/handlers/modpython.py
+++ /dev/null
@@ -1,180 +0,0 @@
-import os
-import sys
-from warnings import warn
-
-from django import http
-from django.core import signals
-from django.core.handlers.base import BaseHandler
-from django.core.urlresolvers import set_script_prefix
-from django.utils import datastructures
-from django.utils.encoding import force_unicode, iri_to_uri
-from django.utils.log import getLogger
-
-logger = getLogger('django.request')
-
-class ModPythonRequest(http.HttpRequest):
-    def __init__(self, req):
-        self._req = req
-        # FIXME: This isn't ideal. The request URI may be encoded (it's
-        # non-normalized) slightly differently to the "real" SCRIPT_NAME
-        # and PATH_INFO values. This causes problems when we compute path_info,
-        # below. For now, don't use script names that will be subject to
-        # encoding/decoding.
-        self.path = force_unicode(req.uri)
-        root = req.get_options().get('django.root', '')
-        self.django_root = root
-        # req.path_info isn't necessarily computed correctly in all
-        # circumstances (it's out of mod_python's control a bit), so we use
-        # req.uri and some string manipulations to get the right value.
-        if root and req.uri.startswith(root):
-            self.path_info = force_unicode(req.uri[len(root):])
-        else:
-            self.path_info = self.path
-        if not self.path_info:
-            # Django prefers empty paths to be '/', rather than '', to give us
-            # a common start character for URL patterns. So this is a little
-            # naughty, but also pretty harmless.
-            self.path_info = u'/'
-        self._post_parse_error = False
-        self._stream = self._req
-        self._read_started = False
-
-    def get_full_path(self):
-        # RFC 3986 requires self._req.args to be in the ASCII range, but this
-        # doesn't always happen, so rather than crash, we defensively encode it.
-        return '%s%s' % (self.path, self._req.args and ('?' + iri_to_uri(self._req.args)) or '')
-
-    def _is_secure(self):
-        try:
-            return self._req.is_https()
-        except AttributeError:
-            # mod_python < 3.2.10 doesn't have req.is_https().
-            return self._req.subprocess_env.get('HTTPS', '').lower() in ('on', '1')
-
-    def _get_request(self):
-        if not hasattr(self, '_request'):
-            self._request = datastructures.MergeDict(self.POST, self.GET)
-        return self._request
-
-    def _get_get(self):
-        if not hasattr(self, '_get'):
-            self._get = http.QueryDict(self._req.args, encoding=self._encoding)
-        return self._get
-
-    def _set_get(self, get):
-        self._get = get
-
-    def _get_post(self):
-        if not hasattr(self, '_post'):
-            self._load_post_and_files()
-        return self._post
-
-    def _set_post(self, post):
-        self._post = post
-
-    def _get_cookies(self):
-        if not hasattr(self, '_cookies'):
-            self._cookies = http.parse_cookie(self._req.headers_in.get('cookie', ''))
-        return self._cookies
-
-    def _set_cookies(self, cookies):
-        self._cookies = cookies
-
-    def _get_files(self):
-        if not hasattr(self, '_files'):
-            self._load_post_and_files()
-        return self._files
-
-    def _get_meta(self):
-        "Lazy loader that returns self.META dictionary"
-        if not hasattr(self, '_meta'):
-            self._meta = {
-                'AUTH_TYPE':         self._req.ap_auth_type,
-                'CONTENT_LENGTH':    self._req.headers_in.get('content-length', 0),
-                'CONTENT_TYPE':      self._req.headers_in.get('content-type'),
-                'GATEWAY_INTERFACE': 'CGI/1.1',
-                'PATH_INFO':         self.path_info,
-                'PATH_TRANSLATED':   None, # Not supported
-                'QUERY_STRING':      self._req.args,
-                'REMOTE_ADDR':       self._req.connection.remote_ip,
-                'REMOTE_HOST':       None, # DNS lookups not supported
-                'REMOTE_IDENT':      self._req.connection.remote_logname,
-                'REMOTE_USER':       self._req.user,
-                'REQUEST_METHOD':    self._req.method,
-                'SCRIPT_NAME':       self.django_root,
-                'SERVER_NAME':       self._req.server.server_hostname,
-                'SERVER_PORT':       self._req.connection.local_addr[1],
-                'SERVER_PROTOCOL':   self._req.protocol,
-                'SERVER_SOFTWARE':   'mod_python'
-            }
-            for key, value in self._req.headers_in.items():
-                key = 'HTTP_' + key.upper().replace('-', '_')
-                self._meta[key] = value
-        return self._meta
-
-    def _get_method(self):
-        return self.META['REQUEST_METHOD'].upper()
-
-    GET = property(_get_get, _set_get)
-    POST = property(_get_post, _set_post)
-    COOKIES = property(_get_cookies, _set_cookies)
-    FILES = property(_get_files)
-    META = property(_get_meta)
-    REQUEST = property(_get_request)
-    method = property(_get_method)
-
-class ModPythonHandler(BaseHandler):
-    request_class = ModPythonRequest
-
-    def __call__(self, req):
-        warn(('The mod_python handler is deprecated; use a WSGI or FastCGI server instead.'),
-             DeprecationWarning)
-
-        # mod_python fakes the environ, and thus doesn't process SetEnv.  This fixes that
-        os.environ.update(req.subprocess_env)
-
-        # now that the environ works we can see the correct settings, so imports
-        # that use settings now can work
-        from django.conf import settings
-
-        # if we need to set up middleware, now that settings works we can do it now.
-        if self._request_middleware is None:
-            self.load_middleware()
-
-        set_script_prefix(req.get_options().get('django.root', ''))
-        signals.request_started.send(sender=self.__class__)
-        try:
-            try:
-                request = self.request_class(req)
-            except UnicodeDecodeError:
-                logger.warning('Bad Request (UnicodeDecodeError)',
-                    exc_info=sys.exc_info(),
-                    extra={
-                        'status_code': 400,
-                    }
-                )
-                response = http.HttpResponseBadRequest()
-            else:
-                response = self.get_response(request)
-        finally:
-            signals.request_finished.send(sender=self.__class__)
-
-        # Convert our custom HttpResponse object back into the mod_python req.
-        req.content_type = response['Content-Type']
-        for key, value in response.items():
-            if key != 'content-type':
-                req.headers_out[str(key)] = str(value)
-        for c in response.cookies.values():
-            req.headers_out.add('Set-Cookie', c.output(header=''))
-        req.status = response.status_code
-        try:
-            for chunk in response:
-                req.write(chunk)
-        finally:
-            response.close()
-
-        return 0 # mod_python.apache.OK
-
-def handler(req):
-    # mod_python hooks into this function.
-    return ModPythonHandler()(req)
diff --git a/django/core/handlers/profiler-hotshot.py b/django/core/handlers/profiler-hotshot.py
deleted file mode 100644
index 0522de6..0000000
--- a/django/core/handlers/profiler-hotshot.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import hotshot
-import os
-import time
-
-from django.core.handlers.modpython import ModPythonHandler
-
-PROFILE_DATA_DIR = "/var/log/cmsprofile"
-
-def handler(req):
-    '''
-    Handler that uses hotshot to store profile data.
-
-    Stores profile data in PROFILE_DATA_DIR.  Since hotshot has no way (that I
-    know of) to append profile data to a single file, each request gets its own
-    profile.  The file names are in the format <url>.<n>.prof where <url> is
-    the request path with "/" replaced by ".", and <n> is a timestamp with
-    microseconds to prevent overwriting files.
-
-    Use the gather_profile_stats.py script to gather these individual request
-    profiles into aggregated profiles by request path.
-    '''
-    profname = "%s.%.3f.prof" % (req.uri.strip("/").replace('/', '.'), time.time())
-    profname = os.path.join(PROFILE_DATA_DIR, profname)
-    prof = hotshot.Profile(profname)
-    return prof.runcall(ModPythonHandler(), req)
diff --git a/django/http/__init__.py b/django/http/__init__.py
index 5f407a4..2f3392f 100644
--- a/django/http/__init__.py
+++ b/django/http/__init__.py
@@ -9,16 +9,11 @@ import warnings
 
 from pprint import pformat
 from urllib import urlencode, quote
-from urlparse import urljoin
+from urlparse import urljoin, parse_qsl
 try:
     from cStringIO import StringIO
 except ImportError:
     from StringIO import StringIO
-try:
-    # The mod_python version is more efficient, so try importing it first.
-    from mod_python.util import parse_qsl
-except ImportError:
-    from urlparse import parse_qsl
 
 import Cookie
 # Some versions of Python 2.7 and later won't need this encoding bug fix:
@@ -348,7 +343,7 @@ class HttpRequest(object):
     ## File-like and iterator interface.
     ##
     ## Expects self._stream to be set to an appropriate source of bytes by
-    ## a corresponding request subclass (WSGIRequest or ModPythonRequest).
+    ## a corresponding request subclass (e.g. WSGIRequest).
     ## Also when request data has already been read by request.POST or
     ## request.body, self._stream points to a StringIO instance
     ## containing that data.
diff --git a/docs/faq/usage.txt b/docs/faq/usage.txt
index 2b185be..1514543 100644
--- a/docs/faq/usage.txt
+++ b/docs/faq/usage.txt
@@ -13,15 +13,6 @@ Make sure that:
 
 * The module doesn't contain syntax errors (of course).
 
-* If you're using mod_python but *not* using Django's request handler,
-  you'll need to work around a mod_python bug related to the use of
-  ``SetEnv``; before you import anything from Django you'll need to do
-  the following::
-
-        os.environ.update(req.subprocess_env)
-
-  (where ``req`` is the mod_python request object).
-
 I can't stand your template language. Do I have to use it?
 ----------------------------------------------------------
 
diff --git a/docs/howto/apache-auth.txt b/docs/howto/apache-auth.txt
index 215c519..719fbc1 100644
--- a/docs/howto/apache-auth.txt
+++ b/docs/howto/apache-auth.txt
@@ -2,17 +2,10 @@
 Authenticating against Django's user database from Apache
 =========================================================
 
-.. warning::
-
-    Support for mod_python has been deprecated within Django. At that
-    time, this method of authentication will no longer be provided by
-    Django. The community is welcome to offer its own alternate
-    solutions using WSGI middleware or other approaches.
-
 Since keeping multiple authentication databases in sync is a common problem when
 dealing with Apache, you can configuring Apache to authenticate against Django's
-:doc:`authentication system </topics/auth>` directly. For example, you
-could:
+:doc:`authentication system </topics/auth>` directly. This requires Apache
+version >= 2.2 and mod_wsgi >= 2.0. For example, you could:
 
 * Serve static/media files directly from Apache only to authenticated users.
 
@@ -22,106 +15,31 @@ could:
 * Allow certain users to connect to a WebDAV share created with mod_dav_.
 
 .. _Subversion: http://subversion.tigris.org/
-.. _mod_dav: http://httpd.apache.org/docs/2.0/mod/mod_dav.html
+.. _mod_dav: http://httpd.apache.org/docs/2.2/mod/mod_dav.html
 
 Configuring Apache
 ==================
 
 To check against Django's authorization database from a Apache configuration
-file, you'll need to use mod_python's ``PythonAuthenHandler`` directive along
-with the standard ``Auth*`` and ``Require`` directives:
+file, you'll need to set 'wsgi' as the value of ``AuthBasicProvider`` or
+``AuthDigestProvider`` directive and then use the ``WSGIAuthUserScript``
+directive to set the path to your authentification script:
 
 .. code-block:: apache
 
     <Location /example/>
         AuthType Basic
         AuthName "example.com"
+        AuthBasicProvider wsgi
+        WSGIAuthUserScript /usr/local/wsgi/scripts/auth.wsgi
         Require valid-user
-
-        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
-        PythonAuthenHandler django.contrib.auth.handlers.modpython
     </Location>
 
-.. admonition:: Using the authentication handler with Apache 2.2
-
-    If you're using Apache 2.2, you'll need to take a couple extra steps.
-
-    You'll need to ensure that ``mod_auth_basic`` and ``mod_authz_user``
-    are loaded. These might be compiled statically into Apache, or you might
-    need to use ``LoadModule`` to load them dynamically (as shown in the
-    example at the bottom of this note).
-
-    You'll also need to insert configuration directives that prevent Apache
-    from trying to use other authentication modules, as well as specifying
-    the ``AuthUserFile`` directive and pointing it to ``/dev/null``. Depending
-    on which other authentication modules you have loaded, you might need one
-    or more of the following directives:
-
-    .. code-block:: apache
-
-        AuthBasicAuthoritative Off
-        AuthDefaultAuthoritative Off
-        AuthzLDAPAuthoritative Off
-        AuthzDBMAuthoritative Off
-        AuthzDefaultAuthoritative Off
-        AuthzGroupFileAuthoritative Off
-        AuthzOwnerAuthoritative Off
-        AuthzUserAuthoritative Off
-
-    A complete configuration, with differences between Apache 2.0 and
-    Apache 2.2 marked in bold, would look something like:
-
-    .. parsed-literal::
-
-        **LoadModule auth_basic_module modules/mod_auth_basic.so**
-        **LoadModule authz_user_module modules/mod_authz_user.so**
-
-        ...
-
-        <Location /example/>
-            AuthType Basic
-            AuthName "example.com"
-            **AuthUserFile /dev/null**
-            **AuthBasicAuthoritative Off**
-            Require valid-user
-
-            SetEnv DJANGO_SETTINGS_MODULE mysite.settings
-            PythonAuthenHandler django.contrib.auth.handlers.modpython
-        </Location>
-
-By default, the authentication handler will limit access to the ``/example/``
-location to users marked as staff members.  You can use a set of
-``PythonOption`` directives to modify this behavior:
-
-================================  =========================================
-``PythonOption``                  Explanation
-================================  =========================================
-``DjangoRequireStaffStatus``      If set to ``on`` only "staff" users (i.e.
-                                  those with the ``is_staff`` flag set)
-                                  will be allowed.
-
-                                  Defaults to ``on``.
-
-``DjangoRequireSuperuserStatus``  If set to ``on`` only superusers (i.e.
-                                  those with the ``is_superuser`` flag set)
-                                  will be allowed.
-
-                                  Defaults to ``off``.
-
-``DjangoPermissionName``          The name of a permission to require for
-                                  access. See :ref:`custom permissions
-                                  <custom-permissions>` for more
-                                  information.
-
-                                  By default no specific permission will be
-                                  required.
-================================  =========================================
+Your auth.wsgi script will have to implement either a
+``check_password(environ, user, password)`` function (for ``AuthBasicProvider``)
+or a ``get_realm_hash(environ, user, realm)`` function (for ``AuthDigestProvider``).
 
-Note that sometimes ``SetEnv`` doesn't play well in this mod_python
-configuration, for reasons unknown. If you're having problems getting
-mod_python to recognize your ``DJANGO_SETTINGS_MODULE``, you can set it using
-``PythonOption`` instead of ``SetEnv``. Therefore, these two Apache directives
-are equivalent::
+See the `mod_wsgi documentation`_ for more details about the implementation
+of such a solution.
 
-    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
-    PythonOption DJANGO_SETTINGS_MODULE mysite.settings
+.. _mod_wsgi documentation: http://code.google.com/p/modwsgi/wiki/AccessControlMechanisms#Apache_Authentication_Provider
diff --git a/docs/howto/deployment/index.txt b/docs/howto/deployment/index.txt
index 113f606..8e27a03 100644
--- a/docs/howto/deployment/index.txt
+++ b/docs/howto/deployment/index.txt
@@ -11,7 +11,6 @@ ways to easily deploy Django:
 
    wsgi/index
    fastcgi
-   mod_python (deprecated) <modpython>
 
 If you're new to deploying Django and/or Python, we'd recommend you try
 :doc:`mod_wsgi </howto/deployment/wsgi/modwsgi>` first. In most cases it'll be
@@ -22,6 +21,6 @@ the easiest, fastest, and most stable deployment choice.
     * `Chapter 12 of the Django Book (second edition)`_ discusses deployment
       and especially scaling in more detail. However, note that this edition
       was written against Django version 1.1 and has not been updated since
-      :doc:`mod_python </howto/deployment/modpython>` was deprecated.
+      `mod_python` was first deprecated, then completely removed in Django 1.5.
 
 .. _chapter 12 of the django book (second edition): http://djangobook.com/en/2.0/chapter12/
diff --git a/docs/howto/deployment/modpython.txt b/docs/howto/deployment/modpython.txt
deleted file mode 100644
index b1ddf58..0000000
--- a/docs/howto/deployment/modpython.txt
+++ /dev/null
@@ -1,415 +0,0 @@
-============================================
-How to use Django with Apache and mod_python
-============================================
-
-.. warning::
-
-    Support for mod_python has been deprecated, and will be removed in
-    Django 1.5. If you are configuring a new deployment, you are
-    strongly encouraged to consider using :doc:`mod_wsgi
-    </howto/deployment/wsgi/modwsgi>` or any of the other :doc:`supported
-    servers </howto/deployment/index>`.
-
-.. highlight:: apache
-
-The `mod_python`_ module for Apache_ can be used to deploy Django to a
-production server, although it has been mostly superseded by the simpler
-:doc:`mod_wsgi deployment option </howto/deployment/wsgi/modwsgi>`.
-
-mod_python is similar to (and inspired by) `mod_perl`_ : It embeds Python within
-Apache and loads Python code into memory when the server starts. Code stays in
-memory throughout the life of an Apache process, which leads to significant
-performance gains over other server arrangements.
-
-Django requires Apache 2.x and mod_python 3.x, and you should use Apache's
-`prefork MPM`_, as opposed to the `worker MPM`_.
-
-.. seealso::
-
-    * Apache is a big, complex animal, and this document only scratches the
-      surface of what Apache can do. If you need more advanced information about
-      Apache, there's no better source than `Apache's own official
-      documentation`_
-
-    * You may also be interested in :doc:`How to use Django with FastCGI, SCGI,
-      or AJP </howto/deployment/fastcgi>`.
-
-.. _Apache: http://httpd.apache.org/
-.. _mod_python: http://www.modpython.org/
-.. _mod_perl: http://perl.apache.org/
-.. _prefork MPM: http://httpd.apache.org/docs/2.2/mod/prefork.html
-.. _worker MPM: http://httpd.apache.org/docs/2.2/mod/worker.html
-.. _apache's own official documentation: http://httpd.apache.org/docs/
-
-Basic configuration
-===================
-
-To configure Django with mod_python, first make sure you have Apache installed,
-with the mod_python module activated.
-
-Then edit your ``httpd.conf`` file and add the following::
-
-    <Location "/mysite/">
-        SetHandler python-program
-        PythonHandler django.core.handlers.modpython
-        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
-        PythonOption django.root /mysite
-        PythonDebug On
-    </Location>
-
-...and replace ``mysite.settings`` with the Python import path to your Django
-project's settings file.
-
-This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the
-Django mod_python handler." It passes the value of :ref:`DJANGO_SETTINGS_MODULE
-<django-settings-module>` so mod_python knows which settings to use.
-
-Because mod_python does not know we are serving this site from underneath the
-``/mysite/`` prefix, this value needs to be passed through to the mod_python
-handler in Django, via the ``PythonOption django.root ...`` line. The value set
-on that line (the last item) should match the string given in the ``<Location
-...>`` directive. The effect of this is that Django will automatically strip the
-``/mysite`` string from the front of any URLs before matching them against your
-URLconf patterns. If you later move your site to live under ``/mysite2``, you
-will not have to change anything except the ``django.root`` option in the config
-file.
-
-When using ``django.root`` you should make sure that what's left, after the
-prefix has been removed, begins with a slash. Your URLconf patterns that are
-expecting an initial slash will then work correctly. In the above example,
-since we want to send things like ``/mysite/admin/`` to ``/admin/``, we need
-to remove the string ``/mysite`` from the beginning, so that is the
-``django.root`` value. It would be an error to use ``/mysite/`` (with a
-trailing slash) in this case.
-
-Note that we're using the ``<Location>`` directive, not the ``<Directory>``
-directive. The latter is used for pointing at places on your filesystem,
-whereas ``<Location>`` points at places in the URL structure of a Web site.
-``<Directory>`` would be meaningless here.
-
-Also, if your Django project is not on the default ``PYTHONPATH`` for your
-computer, you'll have to tell mod_python where your project can be found:
-
-.. parsed-literal::
-
-    <Location "/mysite/">
-        SetHandler python-program
-        PythonHandler django.core.handlers.modpython
-        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
-        PythonOption django.root /mysite
-        PythonDebug On
-        **PythonPath "['/path/to/project'] + sys.path"**
-    </Location>
-
-The value you use for ``PythonPath`` should include the parent directories of
-all the modules you are going to import in your application. It should also
-include the parent directory of the :ref:`DJANGO_SETTINGS_MODULE
-<django-settings-module>` location. This is exactly the same situation as
-setting the Python path for interactive usage. Whenever you try to import
-something, Python will run through all the directories in ``sys.path`` in turn,
-from first to last, and try to import from each directory until one succeeds.
-
-Make sure that your Python source files' permissions are set such that the
-Apache user (usually named ``apache`` or ``httpd`` on most systems) will have
-read access to the files.
-
-An example might make this clearer. Suppose you have some applications under
-``/usr/local/django-apps/`` (for example, ``/usr/local/django-apps/weblog/`` and
-so forth), your settings file is at ``/var/www/mysite/settings.py`` and you have
-specified :ref:`DJANGO_SETTINGS_MODULE <django-settings-module>` as in the above
-example. In this case, you would need to write your ``PythonPath`` directive
-as::
-
-    PythonPath "['/usr/local/django-apps/', '/var/www'] + sys.path"
-
-With this path, ``import weblog`` and ``import mysite.settings`` will both
-work. If you had ``import blogroll`` in your code somewhere and ``blogroll``
-lived under the ``weblog/`` directory, you would *also* need to add
-``/usr/local/django-apps/weblog/`` to your ``PythonPath``. Remember: the
-**parent directories** of anything you import directly must be on the Python
-path.
-
-.. note::
-
-    If you're using Windows, we still recommended that you use forward
-    slashes in the pathnames, even though Windows normally uses the backslash
-    character as its native separator. Apache knows how to convert from the
-    forward slash format to the native format, so this approach is portable and
-    easier to read. (It avoids tricky problems with having to double-escape
-    backslashes.)
-
-    This is valid even on a Windows system::
-
-        PythonPath "['c:/path/to/project'] + sys.path"
-
-You can also add directives such as ``PythonAutoReload Off`` for performance.
-See the `mod_python documentation`_ for a full list of options.
-
-Note that you should set ``PythonDebug Off`` on a production server. If you
-leave ``PythonDebug On``, your users would see ugly (and revealing) Python
-tracebacks if something goes wrong within mod_python.
-
-Restart Apache, and any request to ``/mysite/`` or below will be served by
-Django. Note that Django's URLconfs won't trim the "/mysite/" -- they get passed
-the full URL.
-
-When deploying Django sites on mod_python, you'll need to restart Apache each
-time you make changes to your Python code.
-
-.. _mod_python documentation: http://modpython.org/live/current/doc-html/directives.html
-
-Multiple Django installations on the same Apache
-================================================
-
-It's entirely possible to run multiple Django installations on the same Apache
-instance. Just use ``VirtualHost`` for that, like so::
-
-    NameVirtualHost *
-
-    <VirtualHost *>
-        ServerName www.example.com
-        # ...
-        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
-    </VirtualHost>
-
-    <VirtualHost *>
-        ServerName www2.example.com
-        # ...
-        SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
-    </VirtualHost>
-
-If you need to put two Django installations within the same ``VirtualHost``
-(or in different ``VirtualHost`` blocks that share the same server name),
-you'll need to take a special precaution to ensure mod_python's cache doesn't
-mess things up. Use the ``PythonInterpreter`` directive to give different
-``<Location>`` directives separate interpreters::
-
-    <VirtualHost *>
-        ServerName www.example.com
-        # ...
-        <Location "/something">
-            SetEnv DJANGO_SETTINGS_MODULE mysite.settings
-            PythonInterpreter mysite
-        </Location>
-
-        <Location "/otherthing">
-            SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
-            PythonInterpreter othersite
-        </Location>
-    </VirtualHost>
-
-The values of ``PythonInterpreter`` don't really matter, as long as they're
-different between the two ``Location`` blocks.
-
-Running a development server with mod_python
-============================================
-
-If you use mod_python for your development server, you can avoid the hassle of
-having to restart the server each time you make code changes. Just set
-``MaxRequestsPerChild 1`` in your ``httpd.conf`` file to force Apache to reload
-everything for each request. But don't do that on a production server, or we'll
-revoke your Django privileges.
-
-If you're the type of programmer who debugs using scattered ``print``
-statements, note that output to ``stdout`` will not appear in the Apache
-log and can even `cause response errors`_.
-
-.. _cause response errors: http://blog.dscpl.com.au/2009/04/wsgi-and-printing-to-standard-output.html
-
-If you have the need to print debugging information in a mod_python setup, you
-have a few options. You can print to ``stderr`` explicitly, like so::
-
-    print >> sys.stderr, 'debug text'
-    sys.stderr.flush()
-
-(note that ``stderr`` is buffered, so calling ``flush`` is necessary if you wish
-debugging information to be displayed promptly.)
-
-A more compact approach is to use an assertion::
-
-    assert False, 'debug text'
-
-Another alternative is to add debugging information to the template of your page.
-
-Serving media files
-===================
-
-Django doesn't serve media files itself; it leaves that job to whichever Web
-server you choose.
-
-We recommend using a separate Web server -- i.e., one that's not also running
-Django -- for serving media. Here are some good choices:
-
-* lighttpd_
-* Nginx_
-* TUX_
-* A stripped-down version of Apache_
-* Cherokee_
-
-If, however, you have no option but to serve media or static files on the
-same Apache ``VirtualHost`` as Django, here's how you can turn off mod_python
-for a particular part of the site::
-
-    <Location "/media">
-        SetHandler None
-    </Location>
-
-Just change ``Location`` to the root URL of your media files. You can also use
-``<LocationMatch>`` to match a regular expression.
-
-This example sets up Django at the site root but explicitly disables Django
-for the ``media`` and ``static`` subdirectories and any URL that ends with
-``.jpg``, ``.gif`` or ``.png``::
-
-    <Location "/">
-        SetHandler python-program
-        PythonHandler django.core.handlers.modpython
-        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
-    </Location>
-
-    <Location "/media">
-        SetHandler None
-    </Location>
-
-    <Location "/static">
-        SetHandler None
-    </Location>
-
-    <LocationMatch "\.(jpg|gif|png)$">
-        SetHandler None
-    </LocationMatch>
-
-.. _lighttpd: http://www.lighttpd.net/
-.. _Nginx: http://wiki.nginx.org/Main
-.. _TUX: http://en.wikipedia.org/wiki/TUX_web_server
-.. _Apache: http://httpd.apache.org/
-.. _Cherokee: http://www.cherokee-project.com/
-
-Serving the admin files
-=======================
-
-Note that the Django development server automagically serves the static files
-of the admin app, but this is not the case when you use any other server
-arrangement. You're responsible for setting up Apache, or whichever media
-server you're using, to serve the admin files.
-
-The admin files live in (:file:`django/contrib/admin/static/admin`) of the
-Django distribution.
-
-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the
-admin files (this means using the :djadmin:`collectstatic` management command
-to collect the static files in :setting:`STATIC_ROOT`, and then configuring
-your Web server to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but
-here are two other approaches:
-
-1. Create a symbolic link to the admin static files from within your
-   document root.
-
-2. Or, copy the admin static files so that they live within your Apache
-   document root.
-
-Using "eggs" with mod_python
-============================
-
-If you installed Django from a Python egg_ or are using eggs in your Django
-project, some extra configuration is required. Create an extra file in your
-project (or somewhere else) that contains something like the following:
-
-.. code-block:: python
-
-    import os
-    os.environ['PYTHON_EGG_CACHE'] = '/some/directory'
-
-Here, ``/some/directory`` is a directory that the Apache Web server process can
-write to. It will be used as the location for any unpacking of code the eggs
-need to do.
-
-Then you have to tell mod_python to import this file before doing anything
-else. This is done using the PythonImport_ directive to mod_python. You need
-to ensure that you have specified the ``PythonInterpreter`` directive to
-mod_python as described above__ (you need to do this even if you aren't
-serving multiple installations in this case). Then add the ``PythonImport``
-line in the main server configuration (i.e., outside the ``Location`` or
-``VirtualHost`` sections). For example::
-
-    PythonInterpreter my_django
-    PythonImport /path/to/my/project/file.py my_django
-
-Note that you can use an absolute path here (or a normal dotted import path),
-as described in the `mod_python manual`_. We use an absolute path in the
-above example because if any Python path modifications are required to access
-your project, they will not have been done at the time the ``PythonImport``
-line is processed.
-
-.. _Egg: http://peak.telecommunity.com/DevCenter/PythonEggs
-.. _PythonImport: http://www.modpython.org/live/current/doc-html/dir-other-pimp.html
-.. _mod_python manual: PythonImport_
-__ `Multiple Django installations on the same Apache`_
-
-Error handling
-==============
-
-When you use Apache/mod_python, errors will be caught by Django -- in other
-words, they won't propagate to the Apache level and won't appear in the Apache
-``error_log``.
-
-The exception for this is if something is really wonky in your Django setup. In
-that case, you'll see an "Internal Server Error" page in your browser and the
-full Python traceback in your Apache ``error_log`` file. The ``error_log``
-traceback is spread over multiple lines. (Yes, this is ugly and rather hard to
-read, but it's how mod_python does things.)
-
-If you get a segmentation fault
-===============================
-
-If Apache causes a segmentation fault, there are two probable causes, neither
-of which has to do with Django itself.
-
-1. It may be because your Python code is importing the "pyexpat" module,
-   which may conflict with the version embedded in Apache. For full
-   information, see `Expat Causing Apache Crash`_.
-
-2. It may be because you're running mod_python and mod_php in the same
-   Apache instance, with MySQL as your database backend. In some cases,
-   this causes a known mod_python issue due to version conflicts in PHP and
-   the Python MySQL backend. There's full information in the
-   `mod_python FAQ entry`_.
-
-If you continue to have problems setting up mod_python, a good thing to do is
-get a barebones mod_python site working, without the Django framework. This is
-an easy way to isolate mod_python-specific problems. `Getting mod_python Working`_
-details this procedure.
-
-The next step should be to edit your test code and add an import of any
-Django-specific code you're using -- your views, your models, your URLconf,
-your RSS configuration, etc. Put these imports in your test handler function
-and access your test URL in a browser. If this causes a crash, you've confirmed
-it's the importing of Django code that causes the problem. Gradually reduce the
-set of imports until it stops crashing, so as to find the specific module that
-causes the problem. Drop down further into modules and look into their imports,
-as necessary.
-
-.. _Expat Causing Apache Crash: http://www.dscpl.com.au/wiki/ModPython/Articles/ExpatCausingApacheCrash
-.. _mod_python FAQ entry: http://modpython.org/FAQ/faqw.py?req=show&file=faq02.013.htp
-.. _Getting mod_python Working: http://www.dscpl.com.au/wiki/ModPython/Articles/GettingModPythonWorking
-
-If you get a UnicodeEncodeError
-===============================
-
-If you're taking advantage of the internationalization features of Django (see
-:doc:`/topics/i18n/index`) and you intend to allow users to upload files, you must
-ensure that the environment used to start Apache is configured to accept
-non-ASCII file names. If your environment is not correctly configured, you
-will trigger ``UnicodeEncodeError`` exceptions when calling functions like
-``os.path()`` on filenames that contain non-ASCII characters.
-
-To avoid these problems, the environment used to start Apache should contain
-settings analogous to the following::
-
-    export LANG='en_US.UTF-8'
-    export LC_ALL='en_US.UTF-8'
-
-Consult the documentation for your operating system for the appropriate syntax
-and location to put these configuration items; ``/etc/apache2/envvars`` is a
-common location on Unix platforms. Once you have added these statements
-to your environment, restart Apache.
diff --git a/docs/howto/deployment/wsgi/modwsgi.txt b/docs/howto/deployment/wsgi/modwsgi.txt
index 1aa4009..8398f12 100644
--- a/docs/howto/deployment/wsgi/modwsgi.txt
+++ b/docs/howto/deployment/wsgi/modwsgi.txt
@@ -176,3 +176,24 @@ other approaches:
 
 3. Copy the admin static files so that they live within your Apache
    document root.
+
+If you get a UnicodeEncodeError
+===============================
+
+If you're taking advantage of the internationalization features of Django (see
+:doc:`/topics/i18n/index`) and you intend to allow users to upload files, you must
+ensure that the environment used to start Apache is configured to accept
+non-ASCII file names. If your environment is not correctly configured, you
+will trigger ``UnicodeEncodeError`` exceptions when calling functions like
+``os.path()`` on filenames that contain non-ASCII characters.
+
+To avoid these problems, the environment used to start Apache should contain
+settings analogous to the following::
+
+    export LANG='en_US.UTF-8'
+    export LC_ALL='en_US.UTF-8'
+
+Consult the documentation for your operating system for the appropriate syntax
+and location to put these configuration items; ``/etc/apache2/envvars`` is a
+common location on Unix platforms. Once you have added these statements
+to your environment, restart Apache.
diff --git a/docs/index.txt b/docs/index.txt
index a5d2e13..66c8e73 100644
--- a/docs/index.txt
+++ b/docs/index.txt
@@ -156,7 +156,6 @@ The development process
   :doc:`Overview <howto/deployment/index>` |
   :doc:`WSGI servers <howto/deployment/wsgi/index>` |
   :doc:`FastCGI/SCGI/AJP <howto/deployment/fastcgi>` |
-  :doc:`Apache/mod_python (deprecated) <howto/deployment/modpython>` |
   :doc:`Apache authentication <howto/apache-auth>` |
   :doc:`Handling static files <howto/static-files>` |
   :doc:`Tracking code errors by email <howto/error-reporting>`
diff --git a/docs/ref/contrib/gis/deployment.txt b/docs/ref/contrib/gis/deployment.txt
index c50a378..d98fc51 100644
--- a/docs/ref/contrib/gis/deployment.txt
+++ b/docs/ref/contrib/gis/deployment.txt
@@ -13,11 +13,9 @@ Deploying GeoDjango
 Apache
 ======
 In this section there are some example ``VirtualHost`` directives for
-when deploying using either ``mod_python`` or ``mod_wsgi``.  At this
-time, we recommend ``mod_wsgi``, as it is now officially recommended
-way to deploy Django applications with Apache.  Moreover, if
-``mod_python`` is used, then a prefork version of Apache must also be
-used.  As long as ``mod_wsgi`` is configured correctly, it does not
+when deploying using ``mod_wsgi``, which is now officially the recommended
+way to deploy Django applications with Apache.
+As long as ``mod_wsgi`` is configured correctly, it does not
 matter whether the version of Apache is prefork or worker.
 
 .. note::
@@ -56,42 +54,6 @@ Example::
 For more information, please consult Django's
 :doc:`mod_wsgi documentation </howto/deployment/wsgi/modwsgi>`.
 
-``mod_python``
---------------
-
-.. warning::
-    Support for mod_python will be deprecated in a future release of Django. If
-    you are configuring a new deployment, you are strongly encouraged to
-    consider using :doc:`mod_wsgi </howto/deployment/wsgi/modwsgi>` or any of
-    the other :doc:`supported servers </howto/deployment/index>`.
-
-Example::
-
-    <VirtualHost *:80>
-
-      <Location "/">
-        SetHandler mod_python
-        PythonHandler django.core.handlers.modpython
-        SetEnv DJANGO_SETTINGS_MODULE world.settings
-        PythonDebug On
-        PythonPath "['/var/www/apps'] + sys.path"
-      </Location>
-
-      Alias /media/ "/usr/lib/python2.6/site-packages/django/contrib/admin/media/"
-      <Location "/media">
-        SetHandler None
-      </Location>
-
-    </VirtualHost>
-
-.. warning::
-
-   When using ``mod_python`` you *must* be using a prefork version of Apache, or
-   else your GeoDjango application may crash Apache.
-
-For more information, please consult Django's
-:doc:`mod_python documentation </howto/deployment/modpython>`.
-
 Lighttpd
 ========
 
diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
index c0ae73e..ae736b1 100644
--- a/docs/ref/request-response.txt
+++ b/docs/ref/request-response.txt
@@ -56,15 +56,13 @@ All attributes except ``session`` should be considered read-only.
 .. attribute:: HttpRequest.path_info
 
     Under some Web server configurations, the portion of the URL after the host
-    name is split up into a script prefix portion and a path info portion
-    (this happens, for example, when using the ``django.root`` option
-    with the :doc:`modpython handler from Apache </howto/deployment/modpython>`).
+    name is split up into a script prefix portion and a path info portion.
     The ``path_info`` attribute always contains the path info portion of the
     path, no matter what Web server is being used. Using this instead of
     attr:`~HttpRequest.path` can make your code much easier to move between test
     and deployment servers.
 
-    For example, if the ``django.root`` for your application is set to
+    For example, if the ``WSGIScriptAlias`` for your application is set to
     ``"/minfo"``, then ``path`` might be ``"/minfo/music/bands/the_beatles/"``
     and ``path_info`` would be ``"/music/bands/the_beatles/"``.
 
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
index 1c2849d..73c06ca 100644
--- a/docs/topics/http/urls.txt
+++ b/docs/topics/http/urls.txt
@@ -1020,6 +1020,4 @@ find the base URL of the Django project within its Web server
 (normally, :func:`~django.core.urlresolvers.reverse` takes care of this for
 you). In that case, you can call ``get_script_prefix()``, which will return the
 script prefix portion of the URL for your Django project. If your Django
-project is at the root of its Web server, this is always ``"/"``, but it can be
-changed, for instance  by using ``django.root`` (see :doc:`How to use
-Django with Apache and mod_python </howto/deployment/modpython>`).
+project is at the root of its Web server, this is always ``"/"``.
diff --git a/tests/regressiontests/requests/tests.py b/tests/regressiontests/requests/tests.py
index f986046..5c3cf59 100644
--- a/tests/regressiontests/requests/tests.py
+++ b/tests/regressiontests/requests/tests.py
@@ -4,7 +4,6 @@ from datetime import datetime, timedelta
 from StringIO import StringIO
 
 from django.conf import settings
-from django.core.handlers.modpython import ModPythonRequest
 from django.core.handlers.wsgi import WSGIRequest, LimitedStream
 from django.http import HttpRequest, HttpResponse, parse_cookie, build_request_repr, UnreadablePostError
 from django.test.utils import get_warnings_state, restore_warnings_state
@@ -54,41 +53,6 @@ class RequestsTests(unittest.TestCase):
         self.assertEqual(build_request_repr(request, path_override='/otherpath/', GET_override={u'a': u'b'}, POST_override={u'c': u'd'}, COOKIES_override={u'e': u'f'}, META_override={u'g': u'h'}),
                          u"<WSGIRequest\npath:/otherpath/,\nGET:{u'a': u'b'},\nPOST:{u'c': u'd'},\nCOOKIES:{u'e': u'f'},\nMETA:{u'g': u'h'}>")
 
-    def test_modpythonrequest(self):
-        class FakeModPythonRequest(ModPythonRequest):
-           def __init__(self, *args, **kwargs):
-               super(FakeModPythonRequest, self).__init__(*args, **kwargs)
-               self._get = self._post = self._meta = self._cookies = {}
-
-        class Dummy:
-            def get_options(self):
-                return {}
-
-        req = Dummy()
-        req.uri = 'bogus'
-        request = FakeModPythonRequest(req)
-        self.assertEqual(request.path, 'bogus')
-        self.assertEqual(request.GET.keys(), [])
-        self.assertEqual(request.POST.keys(), [])
-        self.assertEqual(request.COOKIES.keys(), [])
-        self.assertEqual(request.META.keys(), [])
-
-    def test_modpythonrequest_repr(self):
-        class Dummy:
-            def get_options(self):
-                return {}
-        req = Dummy()
-        req.uri = '/somepath/'
-        request = ModPythonRequest(req)
-        request._get = {u'get-key': u'get-value'}
-        request._post = {u'post-key': u'post-value'}
-        request._cookies = {u'post-key': u'post-value'}
-        request._meta = {u'post-key': u'post-value'}
-        self.assertEqual(repr(request), u"<ModPythonRequest\npath:/somepath/,\nGET:{u'get-key': u'get-value'},\nPOST:{u'post-key': u'post-value'},\nCOOKIES:{u'post-key': u'post-value'},\nMETA:{u'post-key': u'post-value'}>")
-        self.assertEqual(build_request_repr(request), repr(request))
-        self.assertEqual(build_request_repr(request, path_override='/otherpath/', GET_override={u'a': u'b'}, POST_override={u'c': u'd'}, COOKIES_override={u'e': u'f'}, META_override={u'g': u'h'}),
-                         u"<ModPythonRequest\npath:/otherpath/,\nGET:{u'a': u'b'},\nPOST:{u'c': u'd'},\nCOOKIES:{u'e': u'f'},\nMETA:{u'g': u'h'}>")
-
     def test_parse_cookie(self):
         self.assertEqual(parse_cookie('invalid:key=true'), {})
 
