Apache con mod_python es actualmente la configuración más robusta para usar Django en un servidor en producción.
mod_python es un plugin de Apache que embebe Python dentro de Apache y carga código Python en memoria cuando el servidor se inicia. El código permanece en memoria a lo largo de la vida del proceso Apache, lo que repercute en aumentos significativos de desempeño comparado con otros arreglos de servidor.
Django requiere Apache 2.x y mod_python 3.x, y nosotros preferimos el módulo de multiprocesamiento (MPM) prefork de Apache, por sobre el MPM worker.
Nota Configurar Apache está claramente más allá del alcance de este libro, por lo que simplemente mencionaremos algunos detalles que necesitamos. Afortunadamente existen grandes recursos disponibles para aprender más sobre Apache. Algunos de los que nos gustan son los siguientes:
- La documentación gratuita de Apache
- Pro Apache, tercera edición (Apress, 2004) de Peter Wainwright,
- Apache: The Definitive Guide, Third Edition (O'Reilly, 2002) de Ben Laurie y Peter Laurie
20.3.1. Configuración básica
Para configurar Django con mod_python, primero debe asegurarse de que tiene
Apache instalado con el módulo mod_python activado. Esto normalmente significa
tener una directiva LoadModule
en tu archivo de configuración de Apache.
Puede parecerse a esto:
LoadModule python_module /usr/lib/apache2/modules/mod_python.so
Luego, edite su archivo de configuración de Apache y agregue lo siguiente:
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE misitio.settings
PythonDebug On
</Location>
Asegurese de reemplazar misitio.settings
por el DJANGO_SETTINGS_MODULE
apropiado para tu sitio.
Esto le dice a Apache, "Usa mod_python para cualquier URL en '/' o bajo ella,
usando el manejado mod_python de Django". Le pasa el valor de
DJANGO_SETTINGS_MODULE
de modo que mod_python conoce que configuración
utilizar.
Nota que estamos usando la directiva <Location>
y no <Directory>
. Esta
última se utiliza para apuntar a lugares de nuestra sistema de archivos,
mientras que <Location>
apunta a lugares en la estructura de la URL de un
sitio web. <Directory>
no tendría sentido aquí.
Apache normalmente se ejecuta como un usuario diferente de tu usuario normal y
puede tener una ruta y un sys.path
distintos. Puedes necesitar decirle a
mod_python
cómo encontrar tu proyecto y a Django mismo:
PythonPath "['/ruta/al/proyecto', '/ruta/a/django'] + sys.path"
También puedes agregar directivas como PythonAutoReload Off
para ajustar
el rendimiento. Mira la documentación de mod_python para un obtener un listado
completo de opciones.
Ten en cuenta que deberías configurar PythonDebug Off
en un servidor de
producción. Si dejas PythonDebug On
, tus usuarios verán mensajes de error no
muy bonitos si algo sale mal dentro de mod_python
.
Reinicia Apache, y cualquier petición a tu sitio (o a tu host virtual si
pusiste las directivas dentro de un bloque <VirtualHost>
) será servida por
Django.
Nota Si implementas Django en un subdirectorio — esto es, en algún lugar más profundo que "/" — Django no recortará el prefijo de la URL para tu URLpatterns. Entonces, si tu configuración de Apache luce como esto:
<Location "/misitio/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE misitio.settings
PythonDebug On
</Location>
entonces todos tus patrones de URL deberán comenzar con "/misitio/"
.
Por esta razón es que normalmente recomendamos implementar Django sobre la
raíz de tu dominio o host virtual. Alternativamente, simplemente puede
hacer descender el nivel de tu URL usando una cuña de URLconf:
urlpatterns = patterns('',
(r'^misitio/', include('normal.root.urls')),
)
20.3.2. Corriendo multiples instalaciones de Django en la misma instancia Apache
Es enteramente posible correr multiples instalaciones de Django en la misma instancia de Apache. Probablemente quieras hacer esto si eres un desarrollador web independiente con multiples clientes pero un sólo un único servidor.
Para lograr esto, simplemente usa VirtualHost
así:
NameVirtualHost *
<VirtualHost *>
ServerName www.ejemplo.com
# ...
SetEnv DJANGO_SETTINGS_MODULE misitio.settings
</VirtualHost>
<VirtualHost *>
ServerName www2.ejemplo.com
# ...
SetEnv DJANGO_SETTINGS_MODULE misitio.other_settings
</VirtualHost>
Si necesitar poner dos instalaciones de Django sobre el mismo VirtualHost
,
necesitar prestar especial atención para asegurarte de que el caché de código
de mod_python no mezcle las cosas. Usa la directiva PythonInterpreter
para
brindar diferentes directivas <Location>
a interpretes distintos:
<VirtualHost *>
ServerName www.ejemplo.com
# ...
<Location "/algo">
SetEnv DJANGO_SETTINGS_MODULE misitio.settings
PythonInterpreter misitio
</Location>
<Location "/otracosa">
SetEnv DJANGO_SETTINGS_MODULE misitio.other_settings
PythonInterpreter misitio_otro
</Location>
</VirtualHost>
Los valores de PythonInterpreter
no importante realmente ya que se encuentran
en dos bloques Location
diferentes.
20.3.3. Corriendo un servidor de desarrollo con mod_python
Debido a que mod_python cachea el código python cargado, cuando implementas
sitios Django sobre mod_python necesitarás reiniciar Apache cada vez que
realizar cambios en tu código. Esto puede ser tedioso, por lo que aqui
compartimos un pequeño truco para evitarlo: simplemente agrega
MaxRequestsPerChild 1
a tu archivo de configuración para forzar a Apache a
recargar todo con cada petición. Pero no hagas esto en un servidor de
producción, o revocaremos tus privilegios Django.
Si eres el tipo de programador que depuran dispersando sentencias print
por
el código (nosotros somos), ten en cuenta que print
no tiene efectos sobre
mod_python; estas no aparecen en el log de Apache como pudrías esperar.
Si necesitas imprimir información de depuración en una configuración
mod_python, probablemente quieras usar el paquete de registro de eventos
estándar de Python (Python's standard logging package). Hay más información
disponible en http://docs.python.org/lib/module-logging.html.
Alternativamente, puedes agregar la información de depuración a las plantillas
de tu página.
20.3.4. Sirviendo Django y archivos multimedia desde la misma instancia Apache
Django no debería ser utilizado para servir archivos multimedia (imagen, audio, video, flash) por sí mismo; mejor deja ese trabajo al servidor web que hayas elegido. Recomendamos usar un servidor Web separado (es decir, uno que no está corriendo a la vez Django) para servir estos archivos. Para más información, mira la sección "Escalabilidad".
Sin embargo, si no tienes opción para servir los archivos multimedia que no sea
el mismo VirtualHost
Apache que usa Django, aquí te mostramos como desactivar
mod_python para una parte particular del sitio:
<Location "/media/">
SetHandler None
</Location>
Cambia Location
a la URL raiz donde se encuentran tus archivos.
Tambien puedes usar <LocationMatch>
para comparar con una expresión regular.
Por ejemplo, esto configura Django en la raiz del sitio pero deshabilitando
Django para el subdirectorio media
y cualquier URL que termine en
.jpg
, .gif
, o .png
:
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</Location>
<Location "/media/">
SetHandler None
</Location>
<LocationMatch "\.(jpg|gif|png)$">
SetHandler None
</LocationMatch>
En todos estos casos, necesitarás configurar la directiva DocumentRoot
para
que Apache sepa dónde encontrar tus archivos estáticos.
20.3.5. Manejo de errores
Cuando usas Apache/mod_python, los errores serán canalizados por Django — en
otras palabras, estos no se propagan al nivel de Apache y no aparecerán en el
error_log
del servidor.
La excepción a esto sucede si algo está realmente desordenado en tu
configuración Django. En este caso, verás una página "Internal Server Error"
en tu navegador, y el volcado de error (traceback) de Python completo en tu
archivo error_log
de Apache. Este volcado de error se difunde por multiples
líneas. (Sí, es feo y bastante difícil de leer, pero así como mod_python hace
las cosas).
20.3.6. Manejando fallas de segmentación
Algunas veces, Apache produce errores de tipo Segmentation faults cuando instalas Django. Cuando esto sucede, se trata casi siempre de una o dos causas no muy relacionadas con Django en sí:
- Puede ser que tu código Python está importando el módulo
pyexpat
(usado para parseo XML), lo que puede entrar en conflicto con la versión embebida en Apache. Para información detallada, revisa "Expat Causing Apache Crash" en http://www.djangoproject.com/r/articles/expat-apache-crash/. - Puede deberse a que estás corriendo mod_python y mod_php sobre la misma instancia de Apache, con MySQL como motor de base de datos. En algunos casos, esto ocasiona un conocido problema que mod_python tiene debido a conflictos de versión en PHP y el back-end MySQL de la base. Hay información detallada en un listado FAQ de mod_python, accesible via http://www.djangoproject.com/r/articles/php-modpython-faq/
Si continuas teniendo problemas para configurar mod_python, una buena cosa para hacer es poner un esqueleto de sitio sobre mod_python a funcionar, sin el framework Django. Esta es una manera fácil de aislar los problemas específicos de mod_python. El artículo "Getting mod_python Working" detalla el procedimiento: http://www.djangoproject.com/r/articles/getting-modpython-working/.
El siguiente paso debería ser editar tu código de pruebas y agregar la importación de cualquier código específico de Django que estes usando — tus vistas, tus modelos, tu URLconf, la configuración de RSS, y así. Incluye estas importaciones en tu función de gestión de pruebas, y accede a la URL correspondiente desde tu navegador. Si esto causa un colapso, habrás confirmado que es la importación de código Django la causa del problema.
Gradualmente reduce el conjunto de importaciones hasta que el colapso
desaparezca, de manera de encontrar el módulo específico que es el culpable.
Profundiza en los módulos y revisa sus importaciones si es necesario. Para más
ayuda, herramientas de sistema como ldconfig
en Linux, otool
en Mac OS, y
ListDLLs
(de SysInternals) en Windows pueden ayudarte a indentificar
dependencias compartidas y posibles conflictos de version.