Fixed #16360 -- Added WSGI entrypoint to startproject layout, and enabled internal servers (runserver and runfcgi) to use an externally-defined WSGI application. Thanks to Armin Ronacher, Jannis Leidel, Alex Gaynor, ptone, and Jacob Kaplan-Moss.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17022 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Carl Meyer 2011-10-22 04:30:10 +00:00
parent dca81ad58a
commit 145a77edc9
34 changed files with 635 additions and 208 deletions

View File

@ -407,6 +407,13 @@ X_FRAME_OPTIONS = 'SAMEORIGIN'
USE_X_FORWARDED_HOST = False USE_X_FORWARDED_HOST = False
# The Python dotted path to the WSGI application that Django's internal servers
# (runserver, runfcgi) will use. If `None`, the return value of
# 'django.core.wsgi.get_wsgi_application' is used, thus preserving the same
# behavior as previous versions of Django. Otherwise this should point to an
# actual WSGI application object.
WSGI_APPLICATION = None
############## ##############
# MIDDLEWARE # # MIDDLEWARE #
############## ##############

View File

@ -99,6 +99,9 @@ MIDDLEWARE_CLASSES = (
ROOT_URLCONF = '{{ project_name }}.urls' ROOT_URLCONF = '{{ project_name }}.urls'
# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = '{{ project_name }}.wsgi.application'
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows. # Always use forward slashes, even on Windows.

View File

@ -0,0 +1,28 @@
"""
WSGI config for {{ project_name }} project.
This module contains the WSGI application used by Django's development server
and any production WSGI deployments. It should expose a module-level variable
named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
this application via the ``WSGI_APPLICATION`` setting.
Usually you will have the standard Django WSGI application here, but it also
might make sense to replace the whole Django WSGI application with a custom one
that later delegates to the Django one. For example, you could introduce WSGI
middleware here, or combine a Django application with an application of another
framework.
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")
# This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
# Apply WSGI middleware here.
# from helloworld.wsgi import HelloWorldApplication
# application = HelloWorldApplication(application)

View File

@ -16,12 +16,14 @@ class Command(BaseRunserverCommand):
def get_handler(self, *args, **options): def get_handler(self, *args, **options):
""" """
Returns the static files serving handler. Returns the static files serving handler wrapping the default handler,
if static files should be served. Otherwise just returns the default
handler.
""" """
handler = super(Command, self).get_handler(*args, **options) handler = super(Command, self).get_handler(*args, **options)
use_static_handler = options.get('use_static_handler', True) use_static_handler = options.get('use_static_handler', True)
insecure_serving = options.get('insecure_serving', False) insecure_serving = options.get('insecure_serving', False)
if (settings.DEBUG and use_static_handler or if use_static_handler and (settings.DEBUG or insecure_serving):
(use_static_handler and insecure_serving)): return StaticFilesHandler(handler)
handler = StaticFilesHandler(handler)
return handler return handler

View File

@ -242,8 +242,8 @@ def get_script_name(environ):
Returns the equivalent of the HTTP request's SCRIPT_NAME environment Returns the equivalent of the HTTP request's SCRIPT_NAME environment
variable. If Apache mod_rewrite has been used, returns what would have been variable. If Apache mod_rewrite has been used, returns what would have been
the script name prior to any rewriting (so it's the script name as seen the script name prior to any rewriting (so it's the script name as seen
from the client's perspective), unless FORCE_SCRIPT_NAME is set (to from the client's perspective), unless the FORCE_SCRIPT_NAME setting is
anything). set (to anything).
""" """
from django.conf import settings from django.conf import settings
if settings.FORCE_SCRIPT_NAME is not None: if settings.FORCE_SCRIPT_NAME is not None:

View File

@ -124,6 +124,7 @@ class LimitedStream(object):
self.buffer = sio.read() self.buffer = sio.read()
return line return line
class WSGIRequest(http.HttpRequest): class WSGIRequest(http.HttpRequest):
def __init__(self, environ): def __init__(self, environ):
script_name = base.get_script_name(environ) script_name = base.get_script_name(environ)
@ -202,13 +203,12 @@ class WSGIRequest(http.HttpRequest):
FILES = property(_get_files) FILES = property(_get_files)
REQUEST = property(_get_request) REQUEST = property(_get_request)
class WSGIHandler(base.BaseHandler): class WSGIHandler(base.BaseHandler):
initLock = Lock() initLock = Lock()
request_class = WSGIRequest request_class = WSGIRequest
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
from django.conf import settings
# Set up middleware if needed. We couldn't do this earlier, because # Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available. # settings weren't available.
if self._request_middleware is None: if self._request_middleware is None:
@ -253,4 +253,3 @@ class WSGIHandler(base.BaseHandler):
response_headers.append(('Set-Cookie', str(c.output(header='')))) response_headers.append(('Set-Cookie', str(c.output(header=''))))
start_response(status, response_headers) start_response(status, response_headers)
return response return response

View File

@ -5,8 +5,7 @@ import sys
import socket import socket
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.core.handlers.wsgi import WSGIHandler from django.core.servers.basehttp import AdminMediaHandler, run, WSGIServerException, get_internal_wsgi_application
from django.core.servers.basehttp import AdminMediaHandler, run, WSGIServerException
from django.utils import autoreload from django.utils import autoreload
naiveip_re = re.compile(r"""^(?: naiveip_re = re.compile(r"""^(?:
@ -37,7 +36,7 @@ class BaseRunserverCommand(BaseCommand):
""" """
Returns the default WSGI handler for the runner. Returns the default WSGI handler for the runner.
""" """
return WSGIHandler() return get_internal_wsgi_application()
def handle(self, addrport='', *args, **options): def handle(self, addrport='', *args, **options):
self.use_ipv6 = options.get('use_ipv6') self.use_ipv6 = options.get('use_ipv6')

View File

@ -18,7 +18,10 @@ from wsgiref import simple_server
from wsgiref.util import FileWrapper # for backwards compatibility from wsgiref.util import FileWrapper # for backwards compatibility
import django import django
from django.core.exceptions import ImproperlyConfigured
from django.core.management.color import color_style from django.core.management.color import color_style
from django.core.wsgi import get_wsgi_application
from django.utils.importlib import import_module
from django.utils._os import safe_join from django.utils._os import safe_join
from django.views import static from django.views import static
@ -27,6 +30,43 @@ from django.contrib.staticfiles import handlers
__all__ = ['WSGIServer', 'WSGIRequestHandler'] __all__ = ['WSGIServer', 'WSGIRequestHandler']
def get_internal_wsgi_application():
"""
Loads and returns the WSGI application as configured by the user in
``settings.WSGI_APPLICATION``. With the default ``startproject`` layout,
this will be the ``application`` object in ``projectname/wsgi.py``.
This function, and the ``WSGI_APPLICATION`` setting itself, are only useful
for Django's internal servers (runserver, runfcgi); external WSGI servers
should just be configured to point to the correct application object
directly.
If settings.WSGI_APPLICATION is not set (is ``None``), we just return
whatever ``django.core.wsgi.get_wsgi_application`` returns.
"""
from django.conf import settings
app_path = getattr(settings, 'WSGI_APPLICATION')
if app_path is None:
return get_wsgi_application()
module_name, attr = app_path.rsplit('.', 1)
try:
mod = import_module(module_name)
except ImportError, e:
raise ImproperlyConfigured(
"WSGI application '%s' could not be loaded; "
"could not import module '%s': %s" % (app_path, module_name, e))
try:
app = getattr(mod, attr)
except AttributeError, e:
raise ImproperlyConfigured(
"WSGI application '%s' could not be loaded; "
"can't find '%s' in module '%s': %s"
% (app_path, attr, module_name, e))
return app
class WSGIServerException(Exception): class WSGIServerException(Exception):
pass pass

View File

@ -139,7 +139,7 @@ def runfastcgi(argset=[], **kwargs):
return False return False
# Prep up and go # Prep up and go
from django.core.handlers.wsgi import WSGIHandler from django.core.servers.basehttp import get_internal_wsgi_application
if options["host"] and options["port"] and not options["socket"]: if options["host"] and options["port"] and not options["socket"]:
wsgi_opts['bindAddress'] = (options["host"], int(options["port"])) wsgi_opts['bindAddress'] = (options["host"], int(options["port"]))
@ -178,7 +178,7 @@ def runfastcgi(argset=[], **kwargs):
fp.write("%d\n" % os.getpid()) fp.write("%d\n" % os.getpid())
fp.close() fp.close()
WSGIServer(WSGIHandler(), **wsgi_opts).run() WSGIServer(get_internal_wsgi_application(), **wsgi_opts).run()
if __name__ == '__main__': if __name__ == '__main__':
runfastcgi(sys.argv[1:]) runfastcgi(sys.argv[1:])

13
django/core/wsgi.py Normal file
View File

@ -0,0 +1,13 @@
from django.core.handlers.wsgi import WSGIHandler
def get_wsgi_application():
"""
The public interface to Django's WSGI support. Should return a WSGI
callable.
Allows us to avoid making django.core.handlers.WSGIHandler public API, in
case the internal WSGI implementation changes or moves in the future.
"""
return WSGIHandler()

View File

@ -23,7 +23,7 @@ usage.
For a development environment -- if you just want to experiment with Django -- For a development environment -- if you just want to experiment with Django --
you don't need to have a separate Web server installed; Django comes with its you don't need to have a separate Web server installed; Django comes with its
own lightweight development server. For a production environment, Django follows own lightweight development server. For a production environment, Django follows
the WSGI spec, :pep:`333`, which means it can run on a variety of server the WSGI spec, :pep:`3333`, which means it can run on a variety of server
platforms. See :doc:`Deploying Django </howto/deployment/index>` for some platforms. See :doc:`Deploying Django </howto/deployment/index>` for some
popular alternatives. Also, the `server arrangements wiki page`_ contains popular alternatives. Also, the `server arrangements wiki page`_ contains
details for several deployment strategies. details for several deployment strategies.

View File

@ -4,10 +4,9 @@ How to use Django with FastCGI, SCGI, or AJP
.. highlight:: bash .. highlight:: bash
Although the current preferred setup for running Django is :doc:`Apache with Although :doc:`WSGI</howto/deployment/wsgi/index>` is the preferred deployment
mod_wsgi </howto/deployment/modwsgi>`, many people use shared hosting, on platform for Django, many people use shared hosting, on which protocols such as
which protocols such as FastCGI, SCGI or AJP are the only viable options. In FastCGI, SCGI or AJP are the only viable options.
some setups, these protocols may provide better performance than mod_wsgi_.
.. admonition:: Note .. admonition:: Note
@ -20,13 +19,13 @@ serve pages to a Web server. The Web server delegates the incoming Web requests
(via a socket) to FastCGI, which executes the code and passes the response back (via a socket) to FastCGI, which executes the code and passes the response back
to the Web server, which, in turn, passes it back to the client's Web browser. to the Web server, which, in turn, passes it back to the client's Web browser.
Like mod_wsgi, FastCGI allows code to stay in memory, allowing requests to be Like WSGI, FastCGI allows code to stay in memory, allowing requests to be
served with no startup time. While mod_wsgi can either be configured embedded served with no startup time. While
in the Apache Web server process or as a separate daemon process, a FastCGI e.g. :doc:`mod_wsgi</howto/deployment/wsgi/modwsgi>` can either be configured
process never runs inside the Web server process, always in a separate, embedded in the Apache Web server process or as a separate daemon process, a
FastCGI process never runs inside the Web server process, always in a separate,
persistent process. persistent process.
.. _mod_wsgi: http://code.google.com/p/modwsgi/
.. _mod_perl: http://perl.apache.org/ .. _mod_perl: http://perl.apache.org/
.. admonition:: Why run code in a separate process? .. admonition:: Why run code in a separate process?

View File

@ -9,13 +9,12 @@ ways to easily deploy Django:
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
modwsgi wsgi/index
uwsgi
fastcgi fastcgi
mod_python (deprecated) <modpython> mod_python (deprecated) <modpython>
If you're new to deploying Django and/or Python, we'd recommend you try If you're new to deploying Django and/or Python, we'd recommend you try
:doc:`mod_wsgi </howto/deployment/modwsgi>` first. In most cases it'll be :doc:`mod_wsgi </howto/deployment/wsgi/modwsgi>` first. In most cases it'll be
the easiest, fastest, and most stable deployment choice. the easiest, fastest, and most stable deployment choice.
.. seealso:: .. seealso::

View File

@ -7,14 +7,14 @@ How to use Django with Apache and mod_python
Support for mod_python has been deprecated, and will be removed in Support for mod_python has been deprecated, and will be removed in
Django 1.5. If you are configuring a new deployment, you are Django 1.5. If you are configuring a new deployment, you are
strongly encouraged to consider using :doc:`mod_wsgi strongly encouraged to consider using :doc:`mod_wsgi
</howto/deployment/modwsgi>` or any of the other :doc:`supported </howto/deployment/wsgi/modwsgi>` or any of the other :doc:`supported
backends </howto/deployment/index>`. servers </howto/deployment/index>`.
.. highlight:: apache .. highlight:: apache
The `mod_python`_ module for Apache_ can be used to deploy Django to a 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 production server, although it has been mostly superseded by the simpler
:doc:`mod_wsgi deployment option </howto/deployment/modwsgi>`. :doc:`mod_wsgi deployment option </howto/deployment/wsgi/modwsgi>`.
mod_python is similar to (and inspired by) `mod_perl`_ : It embeds Python within 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 Apache and loads Python code into memory when the server starts. Code stays in

View File

@ -1,147 +0,0 @@
==========================================
How to use Django with Apache and mod_wsgi
==========================================
Deploying Django with Apache_ and `mod_wsgi`_ is the recommended way to get
Django into production.
.. _Apache: http://httpd.apache.org/
.. _mod_wsgi: http://code.google.com/p/modwsgi/
mod_wsgi is an Apache module which can be used to host any Python application
which supports the Python WSGI interface described in :pep:`3333`, including
Django. Django will work with any version of Apache which supports mod_wsgi.
The `official mod_wsgi documentation`_ is fantastic; it's your source for all
the details about how to use mod_wsgi. You'll probably want to start with the
`installation and configuration documentation`_.
.. _official mod_wsgi documentation: http://code.google.com/p/modwsgi/
.. _installation and configuration documentation: http://code.google.com/p/modwsgi/wiki/InstallationInstructions
Basic configuration
===================
Once you've got mod_wsgi installed and activated, edit your ``httpd.conf`` file
and add::
WSGIScriptAlias / /path/to/mysite/apache/django.wsgi
The first bit above is the url you want to be serving your application at (``/``
indicates the root url), and the second is the location of a "WSGI file" -- see
below -- on your system, usually inside of your project. This tells Apache
to serve any request below the given URL using the WSGI application defined by that file.
Next we'll need to actually create this WSGI application, so create the file
mentioned in the second part of ``WSGIScriptAlias`` and add::
import os
import sys
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
If your project is not on your ``PYTHONPATH`` by default you can add::
path = '/path/to/mysite'
if path not in sys.path:
sys.path.append(path)
just below the ``import sys`` line to place your project on the path. Remember to
replace 'mysite.settings' with your correct settings file, and '/path/to/mysite'
with your own project's location.
.. _serving-files:
Serving files
=============
Django doesn't serve 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 files on the same Apache
``VirtualHost`` as Django, you can set up Apache to serve some URLs as
static media, and others using the mod_wsgi interface to Django.
This example sets up Django at the site root, but explicitly serves
``robots.txt``, ``favicon.ico``, any CSS file, and anything in the
``/static/`` and ``/media/`` URL space as a static file. All other URLs
will be served using mod_wsgi::
Alias /robots.txt /usr/local/wsgi/static/robots.txt
Alias /favicon.ico /usr/local/wsgi/static/favicon.ico
AliasMatch ^/([^/]*\.css) /usr/local/wsgi/static/styles/$1
Alias /media/ /usr/local/wsgi/media/
Alias /static/ /usr/local/wsgi/static/
<Directory /usr/local/wsgi/static>
Order deny,allow
Allow from all
</Directory>
<Directory /usr/local/wsgi/media>
Order deny,allow
Allow from all
</Directory>
WSGIScriptAlias / /usr/local/wsgi/scripts/django.wsgi
<Directory /usr/local/wsgi/scripts>
Order allow,deny
Allow from all
</Directory>
.. _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/
.. More details on configuring a mod_wsgi site to serve static files can be found
.. in the mod_wsgi documentation on `hosting static files`_.
.. _hosting static files: http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Hosting_Of_Static_Files
.. _serving-the-admin-files:
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, 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.
Details
=======
For more details, see the `mod_wsgi documentation on Django integration`_,
which explains the above in more detail, and walks through all the various
options you've got when deploying under mod_wsgi.
.. _mod_wsgi documentation on Django integration: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango

View File

@ -0,0 +1,66 @@
===============================
How to use Django with Gunicorn
===============================
.. highlight:: bash
Gunicorn_ ('Green Unicorn') is a pure-Python WSGI server for UNIX. It has no
dependencies and is easy to install and use.
.. _Gunicorn: http://gunicorn.org/
There are two ways to use Gunicorn with Django. One is to have Gunicorn treat
Django as just another WSGI application. The second is to use Gunicorn's
special `integration with Django`_.
.. _integration with Django: http://gunicorn.org/run.html#django-manage-py_
Installing Gunicorn
===================
Installing gunicorn is as easy as ``pip install gunicorn``. For more details,
see the `gunicorn documentation`_.
.. _gunicorn documentation: http://gunicorn.org/install.html
Running Django in Gunicorn as a generic WSGI application
========================================================
When Gunicorn is installed, a ``gunicorn`` command is available which starts
the Gunicorn server process. At its simplest, gunicorn just needs to be called
with a the location of a WSGI application object.::
gunicorn [OPTIONS] APP_MODULE
Where ``APP_MODULE`` is of the pattern ``MODULE_NAME:VARIABLE_NAME``. The
module name should be a full dotted path. The variable name refers to a WSGI
callable that should be found in the specified module.
So for a typical Django project, invoking gunicorn would look like::
gunicorn myproject.wsgi:application
(This requires that your project be on the Python path; the simplest way to
ensure that is to run this command from the same directory as your
``manage.py`` file.)
Using Gunicorn's Django integration
===================================
To use Gunicorn's built-in Django integration, first add ``"gunicorn"`` to
:setting:`INSTALLED_APPS`. Then run ``python manage.py run_gunicorn``.
This provides a few Django-specific niceties:
* sets the gunicorn process name to be that of the project
* validates installed models
* allows an ``--adminmedia`` option for passing in the location of the
admin media files, mimicing the behavior of runserver.
See Gunicorn's `deployment documentation`_ for additional tips on starting and
maintaining the Gunicorn server.
.. _deployment documentation: http://gunicorn.org/deploy.html

View File

@ -0,0 +1,72 @@
=======================
How to deploy with WSGI
=======================
Django's primary deployment platform is WSGI_, the Python standard for web
servers and applications.
.. _WSGI: http://www.wsgi.org
Django's :djadmin:`startproject` management command sets up a simple default
WSGI configuration for you, which you can tweak as needed for your project, and
direct any WSGI-compliant webserver to use. Django includes getting-started
documentation for the following WSGI servers:
.. toctree::
:maxdepth: 1
modwsgi
gunicorn
uwsgi
The ``application`` object
--------------------------
One key concept of deploying with WSGI is to specify a central ``application``
callable object which the webserver uses to communicate with your code. This is
commonly specified as an object named ``application`` in a Python module
accessible to the server.
.. versionchanged:: 1.4
The :djadmin:`startproject` command creates a :file:`projectname/wsgi.py` that
contains such an application callable.
.. note::
Upgrading from a previous release of Django and don't have a :file:`wsgi.py`
file in your project? You can simply add one to your project's top-level
Python package (probably next to :file:`settings.py` and :file:`urls.py`)
with the contents below. If you want :djadmin:`runserver` to also make use
of this WSGI file, you can also add ``WSGI_APPLICATION =
"mysite.wsgi.application"`` in your settings (replacing ``mysite`` with the
name of your project).
Initially this file contains::
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
# This application object is used by the development server
# as well as any WSGI server configured to use this file.
from django.core.handlers.wsgi import get_wsgi_application
application = get_wsgi_application()
The ``os.environ.setdefault`` line just sets the default settings module to
use, if you haven't explicitly set the :envvar:`DJANGO_SETTINGS_MODULE`
environment variable. You'll need to edit this line to replace ``mysite`` with
the name of your project package, so the path to your settings module is
correct.
To apply `WSGI middleware`_ you can simply wrap the application object
in the same file::
from helloworld.wsgi import HelloWorldApplication
application = HelloWorldApplication(application)
You could also replace the Django WSGI application with a custom WSGI
application that later delegates to the Django WSGI application, if you want to
combine a Django application with a WSGI application of another framework.
.. _`WSGI middleware`: http://www.python.org/dev/peps/pep-3333/#middleware-components-that-play-both-sides

View File

@ -0,0 +1,175 @@
==========================================
How to use Django with Apache and mod_wsgi
==========================================
Deploying Django with Apache_ and `mod_wsgi`_ is a tried and tested way to get
Django into production.
.. _Apache: http://httpd.apache.org/
.. _mod_wsgi: http://code.google.com/p/modwsgi/
mod_wsgi is an Apache module which can host any Python WSGI_ application,
including Django. Django will work with any version of Apache which supports
mod_wsgi.
.. _WSGI: http://www.wsgi.org
The `official mod_wsgi documentation`_ is fantastic; it's your source for all
the details about how to use mod_wsgi. You'll probably want to start with the
`installation and configuration documentation`_.
.. _official mod_wsgi documentation: http://www.modwsgi.org/
.. _installation and configuration documentation: http://www.modwsgi.org/wiki/InstallationInstructions
Basic configuration
===================
Once you've got mod_wsgi installed and activated, edit your Apache server's
``httpd.conf`` file and add::
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
WSGIPythonPath /path/to/mysite.com
<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>
The first bit in the ``WSGIScriptAlias`` line is the base URL path you want to
serve your application at (``/`` indicates the root url), and the second is the
location of a "WSGI file" -- see below -- on your system, usually inside of
your project package (``mysite`` in this example). This tells Apache to serve
any request below the given URL using the WSGI application defined in that
file.
The ``WSGIPythonPath`` line ensures that your project package is available for
import on the Python path; in other words, that ``import mysite`` works.
The ``<Directory>`` piece just ensures that Apache can access your
:file:`wsgi.py` file.
Next we'll need to ensure this :file:`wsgi.py` with a WSGI application object
exists. As of Django version 1.4, :djadmin:`startproject` will have created one
for you; otherwise, you'll need to create it. See the :doc:`WSGI overview
documentation</howto/deployment/wsgi/index>` for the default contents you
should put in this file, and what else you can add to it.
Using a virtualenv
==================
If you install your project's Python dependencies inside a `virtualenv`_,
you'll need to add the path to this virtualenv's ``site-packages`` directory to
your Python path as well. To do this, you can add another line to your
Apache configuration::
WSGIPythonPath /path/to/your/venv/lib/python2.X/site-packages
Make sure you give the correct path to your virtualenv, and replace
``python2.X`` with the correct Python version (e.g. ``python2.7``).
.. _virtualenv: http://www.virtualenv.org
Using mod_wsgi daemon mode
==========================
"Daemon mode" is the recommended mode for running mod_wsgi (on non-Windows
platforms). See the `official mod_wsgi documentation`_ for details on setting
up daemon mode. The only change required to the above configuration if you use
daemon mode is that you can't use ``WSGIPythonPath``; instead you should use
the ``python-path`` option to ``WSGIDaemonProcess``, for example::
WSGIDaemonProcess example.com python-path=/path/to/mysite.com:/path/to/venv/lib/python2.7/site-packages
.. _serving-files:
Serving files
=============
Django doesn't serve 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 files on the same Apache
``VirtualHost`` as Django, you can set up Apache to serve some URLs as
static media, and others using the mod_wsgi interface to Django.
This example sets up Django at the site root, but explicitly serves
``robots.txt``, ``favicon.ico``, any CSS file, and anything in the
``/static/`` and ``/media/`` URL space as a static file. All other URLs
will be served using mod_wsgi::
Alias /robots.txt /path/to/mysite.com/static/robots.txt
Alias /favicon.ico /path/to/mysite.com/static/favicon.ico
AliasMatch ^/([^/]*\.css) /path/to/mysite.com/static/styles/$1
Alias /media/ /path/to/mysite.com/media/
Alias /static/ /path/to/mysite.com/static/
<Directory /path/to/mysite.com/static>
Order deny,allow
Allow from all
</Directory>
<Directory /path/to/mysite.com/media>
Order deny,allow
Allow from all
</Directory>
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Order allow,deny
Allow from all
</Files>
</Directory>
.. _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/
.. More details on configuring a mod_wsgi site to serve static files can be found
.. in the mod_wsgi documentation on `hosting static files`_.
.. _hosting static files: http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Hosting_Of_Static_Files
.. _serving-the-admin-files:
Serving the admin files
=======================
Note that the Django development server automatically serves the static files
of the admin app (and any other installed apps), 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` (along with
a Web server as outlined in the previous section) to handle the admin files, but
here are three other approaches:
1. Create a symbolic link to the admin static files from within your
document root (this may require ``+FollowSymLinks`` in your Apache
configuration).
2. Use an ``Alias`` directive, as demonstrated above, to alias the appropriate
URL (probably :setting:`STATIC_URL` + `admin/`) to the actual location of
the admin files.
3. Copy the admin static files so that they live within your Apache
document root.

View File

@ -36,7 +36,7 @@ uWSGI model
----------- -----------
uWSGI operates on a client-server model. Your Web server (ie. nginx, Apache) uWSGI operates on a client-server model. Your Web server (ie. nginx, Apache)
communicates with a django-uwsgi "worker" process to serve dynamic contents. communicates with a django-uwsgi "worker" process to serve dynamic content.
The Web server can communicate with the uWSGI process either: The Web server can communicate with the uWSGI process either:
* directly by the uWSGI protocol through a socket created by uWSGI, * directly by the uWSGI protocol through a socket created by uWSGI,
@ -48,9 +48,9 @@ systems), or it can use a TCP socket. What you choose is a matterr of
preference. Usually, a TCP socket is easier because connecting to a port preference. Usually, a TCP socket is easier because connecting to a port
doesn't require special permissions. doesn't require special permissions.
In the second case, the Web server doesn't need to do uWSGI protocol. It just In the second case, the Web server doesn't need to speak the uWSGI protocol. It
needs to be able to proxy HTTP requests to the HTTP server built-in uWSGI. just needs to be able to proxy HTTP requests to the HTTP server built-in uWSGI.
The procedure is the same than proxying any HTTP server. Note that the Web The procedure is the same as proxying to any HTTP server. Note that the Web
server is a "reverse proxy" in this case. server is a "reverse proxy" in this case.
Configuring the uWSGI server Configuring the uWSGI server
@ -68,9 +68,9 @@ the uWSGI server.
on that file. on that file.
uWSGI is highly configurable and thus there are many ways to start the uWSGI is highly configurable and thus there are many ways to start the
process. For example, uwsgi version 0.9.6.8 provides a hundred switches. process. For example, uwsgi version 0.9.6.8 provides a hundred switches. This
This guide demonstrates the most important of them, but does not intent to guide demonstrates the most important of them, but is not a substitute the
substitute the official manual and online documentation. official manual and online documentation.
uWSGI supports configuration through: uWSGI supports configuration through:
@ -98,8 +98,8 @@ uWSGI server. This means:
* the uWSGI server can be restarted or reloaded independently from the Web * the uWSGI server can be restarted or reloaded independently from the Web
server, server,
* (except with Cheerokee), it is the role of the system administrator to make * (except with Cherokee), it is the role of the system administrator to make
uWSGI to start on boot or reboot: either through tools like supervisor or uWSGI start on boot or reboot: either through tools like supervisor or
daemontools, either directly at init level in a file like /etc/rc.local or daemontools, either directly at init level in a file like /etc/rc.local or
/etc/conf.d/local /etc/conf.d/local
@ -109,11 +109,11 @@ Managing uWSGI
Starting the server Starting the server
------------------- -------------------
Example command line for a Web server that understand the uWSGI protocol:: Example command line for a Web server that understands the uWSGI protocol::
uwsgi --chdir=/path/to/your/project uwsgi --chdir=/path/to/your/project
--module='django.core.handlers.wsgi:WSGIHandler()' \ --module='mysite.wsgi:application' \
--env DJANGO_SETTINGS_MODULE=settings \ --env DJANGO_SETTINGS_MODULE=mysite.settings \
--master --pidfile=/tmp/project-master.pid \ --master --pidfile=/tmp/project-master.pid \
--socket=127.0.0.1:49152 \ # can also be a file --socket=127.0.0.1:49152 \ # can also be a file
--processes=5 \ # number of worker processes --processes=5 \ # number of worker processes
@ -125,17 +125,27 @@ Example command line for a Web server that understand the uWSGI protocol::
--home=/path/to/virtual/env \ # optionnal path to a virtualenv --home=/path/to/virtual/env \ # optionnal path to a virtualenv
--daemonize=/var/log/uwsgi/yourproject.log # background the process --daemonize=/var/log/uwsgi/yourproject.log # background the process
Django specific options are: This assumes that you have a top-level project package named ``mysite``, and
within it a module :file:`mysite/wsgi.py` that contains a WSGI ``application``
object. This is the layout you will have if you ran ``django-admin.py
startproject mysite`` (using your own project name in place of ``mysite``) with
a recent version of Django. If this file does not exist, you'll need to create
it. See the :doc:`/howto/deployment/wsgi/index` documentation for the default
contents you should put in this file, and what else you can add to it.
* ``chdir``: should be the path to your project The Django-specific options here are:
* ``module``: uwsgi module to use
* ``pythonpath``: optional path to your project virtualenv * ``chdir``: the path to the directory that needs to be on Python's import path; i.e. the directory containing the ``mysite`` package.
* ``env``: should contain at least ``DJANGO_SETTINGS_MODULE`` * ``module``: The WSGI module to use, probably the ``mysite.wsgi`` module which
:djadmin:`startproject` creates.
* ``env``: should probably contain at least ``DJANGO_SETTINGS_MODULE``
* ``home``: optional path to your project virtualenv
Example ini configuration file:: Example ini configuration file::
[uwsgi] [uwsgi]
chdir=/path/to/your/project chdir=/path/to/your/project
module='mysite.wsgi:application'
master=True master=True
pidfile=/tmp/project-master.pid pidfile=/tmp/project-master.pid
vacuum=True vacuum=True
@ -157,7 +167,7 @@ Read more `uWSGI configuration examples
Reloading the daemon Reloading the daemon
-------------------- --------------------
As mentioned above, the uWSGI master process is one of the core component of As mentioned above, the uWSGI master process is one of the core components of
the uWSGI stack. The signal to brutally reload all the workers and the master the uWSGI stack. The signal to brutally reload all the workers and the master
process is SIGTERM. Example command to brutally reload the uWSGI processes:: process is SIGTERM. Example command to brutally reload the uWSGI processes::
@ -167,7 +177,7 @@ Patching the daemon
------------------- -------------------
One of the great advantages of uWSGI is its ability to gradually restart each One of the great advantages of uWSGI is its ability to gradually restart each
worker without loosing any request. worker without losing any requests.
For example, uWSGI can be signaled that worker should reload the code after For example, uWSGI can be signaled that worker should reload the code after
handling their current request (if any) from bash:: handling their current request (if any) from bash::
@ -236,7 +246,7 @@ still experimental.
Troubleshooting Troubleshooting
=============== ===============
As usual, the first things to do is to check the logs. This implies: As usual, the first thing to do is to check the logs. This implies:
* the web server log, which will indicate if it couldn't connect to the uWSGI * the web server log, which will indicate if it couldn't connect to the uWSGI
process, process,
@ -251,5 +261,5 @@ Typical gotchas:
killed with ``SIGKILL``, it won't remove the socket and pidfile when it is killed with ``SIGKILL``, it won't remove the socket and pidfile when it is
interrupted. It is safe to remove them manually and to start uWSGI again in interrupted. It is safe to remove them manually and to start uWSGI again in
that case. that case.
* uWSGI can start the process on the foreground, this will make errors easily * uWSGI can start the process in the foreground, this will make errors easily
visible to the system administrator. visible to the system administrator.

View File

@ -154,10 +154,9 @@ The development process
* **Deployment:** * **Deployment:**
:doc:`Overview <howto/deployment/index>` | :doc:`Overview <howto/deployment/index>` |
:doc:`Apache/mod_wsgi <howto/deployment/modwsgi>` | :doc:`WSGI servers <howto/deployment/wsgi/index>` |
:doc:`uWSGI <howto/deployment/uwsgi>` |
:doc:`Apache/mod_python (deprecated) <howto/deployment/modpython>` |
:doc:`FastCGI/SCGI/AJP <howto/deployment/fastcgi>` | :doc:`FastCGI/SCGI/AJP <howto/deployment/fastcgi>` |
:doc:`Apache/mod_python (deprecated) <howto/deployment/modpython>` |
:doc:`Apache authentication <howto/apache-auth>` | :doc:`Apache authentication <howto/apache-auth>` |
:doc:`Handling static files <howto/static-files>` | :doc:`Handling static files <howto/static-files>` |
:doc:`Tracking code errors by email <howto/error-reporting>` :doc:`Tracking code errors by email <howto/error-reporting>`

View File

@ -95,6 +95,7 @@ Let's look at what :djadmin:`startproject` created::
__init__.py __init__.py
settings.py settings.py
urls.py urls.py
wsgi.py
.. admonition:: Doesn't match what you see? .. admonition:: Doesn't match what you see?
@ -129,6 +130,9 @@ These files are:
"table of contents" of your Django-powered site. You can read more about "table of contents" of your Django-powered site. You can read more about
URLs in :doc:`/topics/http/urls`. URLs in :doc:`/topics/http/urls`.
* :file:`mysite/wsgi.py`: An entry-point for WSGI-compatible webservers to
serve your project. See :doc:`/howto/deployment/wsgi/index` for more details.
.. _more about packages: http://docs.python.org/tutorial/modules.html#packages .. _more about packages: http://docs.python.org/tutorial/modules.html#packages
The development server The development server

View File

@ -54,7 +54,7 @@ Example::
number of ``processes`` instead. number of ``processes`` instead.
For more information, please consult Django's For more information, please consult Django's
:doc:`mod_wsgi documentation </howto/deployment/modwsgi>`. :doc:`mod_wsgi documentation </howto/deployment/wsgi/modwsgi>`.
``mod_python`` ``mod_python``
-------------- --------------
@ -62,8 +62,8 @@ For more information, please consult Django's
.. warning:: .. warning::
Support for mod_python will be deprecated in a future release of Django. If 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 you are configuring a new deployment, you are strongly encouraged to
consider using :doc:`mod_wsgi </howto/deployment/modwsgi>` or any of the consider using :doc:`mod_wsgi </howto/deployment/wsgi/modwsgi>` or any of
other :doc:`supported backends </howto/deployment/index>`. the other :doc:`supported servers </howto/deployment/index>`.
Example:: Example::

View File

@ -504,6 +504,10 @@ supports the FastCGI protocol. See the :doc:`FastCGI deployment documentation
</howto/deployment/fastcgi>` for details. Requires the Python FastCGI module from </howto/deployment/fastcgi>` for details. Requires the Python FastCGI module from
`flup`_. `flup`_.
.. versionadded:: 1.4
Internally, this wraps the WSGI application object specified by the
:setting:`WSGI_APPLICATION` setting.
.. _flup: http://www.saddi.com/software/flup/ .. _flup: http://www.saddi.com/software/flup/
The options accepted by this command are passed to the FastCGI library and The options accepted by this command are passed to the FastCGI library and
@ -628,6 +632,10 @@ If you run this script as a user with normal privileges (recommended), you
might not have access to start a port on a low port number. Low port numbers might not have access to start a port on a low port number. Low port numbers
are reserved for the superuser (root). are reserved for the superuser (root).
.. versionadded:: 1.4
This server uses the WSGI application object specified by the
:setting:`WSGI_APPLICATION` setting.
DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through
security audits or performance tests. (And that's how it's gonna stay. We're in security audits or performance tests. (And that's how it's gonna stay. We're in
the business of making Web frameworks, not Web servers, so improving this the business of making Web frameworks, not Web servers, so improving this

View File

@ -2095,6 +2095,25 @@ A boolean that specifies whether to use the X-Forwarded-Host header in
preference to the Host header. This should only be enabled if a proxy preference to the Host header. This should only be enabled if a proxy
which sets this header is in use. which sets this header is in use.
.. setting:: WSGI_APPLICATION
WSGI_APPLICATION
----------------
.. versionadded:: 1.4
Default: ``None``
The full Python path of the WSGI application object that Django's built-in
servers (e.g. :djadmin:`runserver`) will use. The :djadmin:`django-admin.py
startproject <startproject>` management command will create a simple
``wsgi.py`` file with an ``application`` callable in it, and point this setting
to that ``application``.
If not set, the return value of :func:`django.core.wsgi.get_wsgi_application`
will be used. In this case, the behavior of :djadmin:`runserver` will be
identical to previous Django versions.
.. setting:: YEAR_MONTH_FORMAT .. setting:: YEAR_MONTH_FORMAT
YEAR_MONTH_FORMAT YEAR_MONTH_FORMAT

View File

@ -303,7 +303,7 @@ more flexible ``mod_wsgi`` backend.
If you are currently using the ``mod_python`` request handler, you are strongly If you are currently using the ``mod_python`` request handler, you are strongly
encouraged to redeploy your Django instances using :doc:`mod_wsgi encouraged to redeploy your Django instances using :doc:`mod_wsgi
</howto/deployment/modwsgi>`. </howto/deployment/wsgi/modwsgi>`.
Function-based generic views Function-based generic views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -688,7 +688,7 @@ more flexible ``mod_wsgi`` backend.
If you are currently using the ``mod_python`` request handler, you If you are currently using the ``mod_python`` request handler, you
should redeploy your Django projects using another request handler. should redeploy your Django projects using another request handler.
:doc:`mod_wsgi </howto/deployment/modwsgi>` is the request handler :doc:`mod_wsgi </howto/deployment/wsgi/modwsgi>` is the request handler
recommended by the Django project, but :doc:`FastCGI recommended by the Django project, but :doc:`FastCGI
</howto/deployment/fastcgi>` is also supported. Support for </howto/deployment/fastcgi>` is also supported. Support for
``mod_python`` deployment will be removed in Django 1.5. ``mod_python`` deployment will be removed in Django 1.5.

View File

@ -403,6 +403,24 @@ prefix, some places without it), the imports will need to be cleaned up when
switching to the new ``manage.py``. switching to the new ``manage.py``.
Improved WSGI support
~~~~~~~~~~~~~~~~~~~~~
The :djadmin:`startproject` management command now adds a :file:`wsgi.py`
module to the initial project layout, containing a simple WSGI application that
can be used for :doc:`deploying with WSGI app
servers</howto/deployment/wsgi/index>`.
The :djadmin:`built-in development server<runserver>` now supports using an
externally-defined WSGI callable, so as to make it possible to run runserver
with the same WSGI configuration that is used for deployment. A new
:setting:`WSGI_APPLICATION` setting is available to configure which WSGI
callable :djadmin:`runserver` uses.
(The :djadmin:`runfcgi` management command also internally wraps the WSGI
callable configured via :setting:`WSGI_APPLICATION`.)
Minor features Minor features
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

View File

@ -48,7 +48,7 @@ documentation to determine which mode is right for your setup. Make
sure you have Apache installed, with the mod_wsgi module activated. sure you have Apache installed, with the mod_wsgi module activated.
Django will work with any version of Apache that supports mod_wsgi. Django will work with any version of Apache that supports mod_wsgi.
See :doc:`How to use Django with mod_wsgi </howto/deployment/modwsgi>` See :doc:`How to use Django with mod_wsgi </howto/deployment/wsgi/modwsgi>`
for information on how to configure mod_wsgi once you have it for information on how to configure mod_wsgi once you have it
installed. installed.

View File

@ -75,7 +75,7 @@ application what settings file to use. Do that with ``os.environ``::
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
Read the :doc:`Django mod_wsgi documentation Read the :doc:`Django mod_wsgi documentation
</howto/deployment/modwsgi>` for more information and other common </howto/deployment/wsgi/modwsgi>` for more information and other common
elements to a Django WSGI application. elements to a Django WSGI application.
Default settings Default settings

View File

View File

View File

@ -0,0 +1,102 @@
from __future__ import with_statement
from django.core.exceptions import ImproperlyConfigured
from django.core.servers.basehttp import get_internal_wsgi_application
from django.core.wsgi import get_wsgi_application
from django.test import TestCase
from django.test.client import RequestFactory
from django.test.utils import override_settings
from django.utils import unittest
class WSGITest(TestCase):
urls = "regressiontests.wsgi.urls"
def test_get_wsgi_application(self):
"""
Verify that ``get_wsgi_application`` returns a functioning WSGI
callable.
"""
application = get_wsgi_application()
environ = RequestFactory()._base_environ(
PATH_INFO="/",
CONTENT_TYPE="text/html; charset=utf-8",
REQUEST_METHOD="GET"
)
response_data = {}
def start_response(status, headers):
response_data["status"] = status
response_data["headers"] = headers
response = application(environ, start_response)
self.assertEqual(response_data["status"], "200 OK")
self.assertEqual(
response_data["headers"],
[('Content-Type', 'text/html; charset=utf-8')])
self.assertEqual(
unicode(response),
u"Content-Type: text/html; charset=utf-8\n\nHello World!")
class GetInternalWSGIApplicationTest(unittest.TestCase):
@override_settings(WSGI_APPLICATION="regressiontests.wsgi.wsgi.application")
def test_success(self):
"""
If ``WSGI_APPLICATION`` is a dotted path, the referenced object is
returned.
"""
app = get_internal_wsgi_application()
from .wsgi import application
self.assertTrue(app is application)
@override_settings(WSGI_APPLICATION=None)
def test_default(self):
"""
If ``WSGI_APPLICATION`` is ``None``, the return value of
``get_wsgi_application`` is returned.
"""
# Mock out get_wsgi_application so we know its return value is used
fake_app = object()
def mock_get_wsgi_app():
return fake_app
from django.core.servers import basehttp
_orig_get_wsgi_app = basehttp.get_wsgi_application
basehttp.get_wsgi_application = mock_get_wsgi_app
try:
app = get_internal_wsgi_application()
self.assertTrue(app is fake_app)
finally:
basehttp.get_wsgi_application = _orig_get_wsgi_app
@override_settings(WSGI_APPLICATION="regressiontests.wsgi.noexist.app")
def test_bad_module(self):
with self.assertRaises(ImproperlyConfigured) as cm:
get_internal_wsgi_application()
self.assertEqual(
str(cm.exception),
"WSGI application 'regressiontests.wsgi.noexist.app' could not be loaded; could not import module 'regressiontests.wsgi.noexist': No module named noexist")
@override_settings(WSGI_APPLICATION="regressiontests.wsgi.wsgi.noexist")
def test_bad_name(self):
with self.assertRaises(ImproperlyConfigured) as cm:
get_internal_wsgi_application()
self.assertEqual(
str(cm.exception),
"WSGI application 'regressiontests.wsgi.wsgi.noexist' could not be loaded; can't find 'noexist' in module 'regressiontests.wsgi.wsgi': 'module' object has no attribute 'noexist'")

View File

@ -0,0 +1,10 @@
from django.conf.urls import url, patterns
from django.http import HttpResponse
def helloworld(request):
return HttpResponse("Hello World!")
urlpatterns = patterns(
"",
url("^$", helloworld)
)

View File

@ -0,0 +1,2 @@
# This is just to test finding, it doesn't have to be a real WSGI callable
application = object()