Comment utiliser Django avec mod_python
Apache avec mod_python est actuellement la configuration recommandée pour un serveur de production.
mod_python est similaire à mod_perl : Il embarque Python au sein d'Apache et charge Python en mémoire lorsque le serveur démarre. Python reste en mémoire tout le temps sans être lié aux process Apache, ce qui conduit à un gain de performance sensible.
Django requiert Apache 2.x et mod_python 3.x, et vous devriez utiliser Apache en mode prefork MPM, et non pas en mode worker MPM.
Vous pouvez aussi être intéressé par Comment utilisez Django avec FastCGI, SCGI ou AJP (qui couvre aussi SCGI et AJP).
Configuration basique
Pour configurer Django avec mod_python, assurez vous qu'Apache est installé, et que mod_python est activé.
Ensuite éditez votre fichier httpd.conf et ajoutez-y ce qui suit:
<Location "/mysite/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>
...et remplacez mysite.settings par le nom du répertoire de votre projet Django où se trouve votre fichier settings.py.
Cela indique à Apache : "Utilise mod_python pour toutes les URL sous le chemin '/mysite/', en utilisant l'handler Django de mod_python." Cela lui fournit la valeur définie pour DJANGO_SETTINGS_MODULE et ainsi, mod_python sait quels paramètres utiliser.
Notez que nous utilisons la directive <Location> et non <Directory>. Cette dernière est utilisée pour pointer sur des emplacements dans votre système de fichiers, alors que <Location> porte sur le motif de l'url de votre site web. <Directory> n'a aucun sens ici.
En outre, si votre projet Django n'est pas dans le PYTHONPATH par défaut de votre ordinateur, vous devez indiquer à mod_python où se situe le projet :
<Location "/mysite/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
PythonPath "['/path/to/project'] + sys.path"
</Location>
La valeur que vous utilisez pour le PythonPath doit contenir tous les répertoires parents des modules que vous importez dans votre application. Elle doit aussi contenir le dossier parent de votre fichier DJANGO_SETTINGS_MODULE. Cela est en tout point similaire à la définition du Python Path pour un usage interactif. A chaque fois que vous tentez d'importer quelque chose, Python va regarder dans les répertoires de votre sys.path, du premier au dernier, puis va tenter d'importer le(s) module(s) depuis chaque répertoire jusqu'au chargement effectif du module.
Un exemple pour éclaircir ces propos : Supposez que vous avez une application située dans /usr/local/django-apps/ (par exemple : /usr/local/django-apps/weblog/), que votre fichier de paramètres est /var/www/mysite/settings.py et que vous avez défini DJANGO_SETTINGS_MODULE comme dans l'exemple précédent. Dans ce cas, vous allez définir votre directive PythonPath directive de la façon suivante:
PythonPath "['/usr/local/django-apps/', '/var/www'] + sys.path"
Avec ce chemin, import weblog and import mysite.settings vont fonctionner. Si vous avez import blogroll dans votre code et si blogroll est située dans le répertoire weblog/, alors vous devez également ajouter /usr/local/django-apps/weblog/ à votre directive PythonPath. Rappel: Le répertoire parent de tout ce que vous importez doit être défini dans votre Python path.
Note
Si vous utilisez Windows, il est recommandé d'utiliser les "slashs" dans la désignation du chemin, même si les "anti-slashs" sont utilisés nativement. Apache sait comment convertir les slashs en anti-slashs. En procédant ainsi, votre configuration est portable sur un autre environnement et gagne en lisibilité (cela évite surtout d'échapper vos anti-slashs).
Ceci est valide même sous un système Windows:
PythonPath "['c:/path/to/project'] + sys.path"
Vous pouvez aussi ajouter des directives telles que PythonAutoReload Off pour améliorer les performances. Référez vous à la documentation de mod_python pour la liste complète des options.
Notez que vous devez utiliser PythonDebug Off sur un serveur de production. Si vous avez PythonDebug On, vos utilisateurs vont voir les tracebacks Python hideux et révélateur en cas d'erreurs avec mod_python.
Redémarrez Apache, et toutes les requêtes vers /mysite/ seront servies par Django. Note que la configuration des urls de Django n'analyse pas "/mysite/" -- c'est bien toute l'url qui lui est passé.
Quand vous déployez des sites réalisés avec Django avec mod_python, vous devrez redémarrez Apache à chaque fois que vous modifiez votre code Python.
Installations multiples de Django au sein d'une seule instance Apache
Il est tout à fait possible d'exécuter plusieurs instances de Django sur la même instance Apache. Il faut juste utiliser les VirtualHost` comme indiqué ci-dessous
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>
Si vous avez besoin d'utiliser plusieurs instances au sein du même VirtualHost, vous devez vous assurer que le cache de mod_python n'ait pas d'effets de bord. Utiliser la directive PythonInterpreter au sein de chaque section <Location> pour contourner le problème:
<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>
Les valeurs données à PythonInterpreter importent peu tant qu'elles sont différentes pour chaque section Location.
Mettre en place un serveur de développement avec mod_python
Si vous utilisez mod_python en tant que serveur de développement, vous pouvez éviter la contrainte de redémarrer le serveur à chaque modification de code. Il vous suffit de définir MaxRequestsPerChild 1 dans votre fichier httpd.conf pour forcer Apache à se recharger à chaque requête. Mais ne faites surtout pas ça sur un serveur de production, faute de quoi nous vous interdirions de jouer avec Django.
Si vous êtes le genre de programmeur à débugguer en utilisant des instructions print, notez que l'instruction print n'a aucun effet sous mod_python ; Elle n'apparaît pas dans le log d'apache comme certains s'y attendent. Si vous avez besoin d'afficher les informations de débuggage sous mod_python, utilisez plutôt
assert False, the_value_i_want_to_see
Ou ajoutez les informations de débuggage dans votre modèle de page.
Servir les fichiers média
Django ne sert pas de lui-même les fichiers media. Il laisse cette tâche au serveur web que vous avez choisi.
Nous recommandons l'utilisation d'un serveur web distinct, i.e. un qui soit différent de celui sur lequel tourne Django, pour servir les fichiers media. Ci-après quelques bons choix :
Si, toutefois, vous n'avez pas cette possibilité et devez servir les fichiers media sur le même hôte virtuel Apache, voici comment désactivez mod_python pour une partie du site
<Location "/media/">
SetHandler None
</Location>
Adaptez Location en fonction de l'url racine de vos fichiers media. Vous pouvez aussi utiliser la directive <LocationMatch> pour satisfaire une expression régulière.
L'exemple suivant définit que Django est à la racine du site mais le désactive pour le dossier media et toute url se terminant par .jpg, .gif ou .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>
Servir les fichiers media d'admin
Notez que le serveur de développement de Django sert automatiquement les fichiers media d'admin mais ce n'est plus le cas si vous utilisez une autre configuration. Vous devez configurer Apache, ou tout autre serveur web utilisé, pour servir les fichiers d'admin.
Les fichiers d'admin sont situés dans (django/contrib/admin/media) dans la distribution de Django.
Ci-après les deux approches recommandées :
- Créer un lien symbolique vers les fichiers media d'admin depuis la racine de votre site. Ainsi, tous les fichiers dépendants de Django (code et modèles) demeurent à un seul endroit, et vous serez toujours en mesure de mettre à jour votre code vers les derniers gabarits d'admin via svn update, si ces gabarits changent.
- Ou copiez les fichiers media d'admin de telle sorte qu'ils soient présents à la racine de votre site.
Utiliser des eggs avec mod_python
Si vous avez installé Django à partir d'un egg ou si vous utilisez des eggs dans votre projet Django, une opération supplémentaire est requise. Créez un fichier dans votre projet (ou ailleurs) contenant les éléments suivants:
import os os.environ['PYTHON_EGG_CACHE'] = '/some/directory'
Ici, /some/directory est un répertoire dans lequel Apache doit pouvoir écrire. Les eggs vont utiliser ce répertoire pour y placer tout le code nécessaire à leur fonctionnement
Ensuite, vous devez indiquer à mod_python qu'il lui faut importer ce fichier avant de faire quoi que ce soit. Cela se fait en utilisant la directive PythonImport de mod_python. Vous devez vous assurer que vous avez bien défini la directive PythonInterpreter pour mod_python comme décrit précédemment (vous devez faire cela même si vous n'utilisez pas les installations multiples).
Ensuite, ajoutez la ligne PythonImport dans le fichier de configuration principal de votre serveur (c'est à dire en dehors des sections Location ou VirtualHost). Par exemple:
PythonInterpreter my_django PythonImport /path/to/my/project/file.py my_django
Note : vous pouvez utiliser un chemin absolu (ou un chemin d'import normal, marqué par des points), comme décrit dans le manuel de mod_python. Nous utilisons un chemin absolu dans l'exemple ci-dessus, car, si n'importe quelle modification du path python est requise pour accéder à votre projet, elle ne sera pas effectuée lorsque la ligne PythonImport est interprétée.
Gestion des erreurs
- Quand vous utilisez Apache/mod_python, les erreurs seront attrapées par Django
- -- en d'autres mots elles ne seront pas remontées à Apache et n'apparaîtront pas dans le fichier error_log de ce dernier.
La seule exception est que si quelque chose de vraiment étrange est présent dans la configuration de votre instance Django. Dans ce cas, vous verrez une page "Internal Server Error" dans votre navigateur et le traceback python complet dans le fichier error_log d'Apache. Le "traceback" dans le error_log est réparti sur plusieurs linges. (Oui, c'est moche et plus complexe à lire mais c'est la façon dont mod_python gère les choses.)
Si vous obtenez une erreur de segmentation (segmentation fault)
Si Apache provoque une erreur de segmentation, il y a deux causes probables qui ne sont pas imputables à Django.
- Cela est peut être dû à votre code python qui importe le module "pyexpat", qui peut rentrer en conflit avec la version embarquée dans Apache. Pour plus d'information, consultez Expat Causing Apache Crash.
- Cela peut être du au fait que vous faites tourner mod_python et mod_php dans la même instance d'apache avec MySQL comme base de données. Dans certains cas, cela cause une erreur connue de mod_python due à un conflit de version entre le backend Python et PHP de MySQL. Plus d'information dans l'entrée de la FAQ de mod_python.
Si les problèmes persistent dans votre mise en place de mod_python, une bonne chose à faire est de tester un site sous mod_python et qui n'a pas été réalisé avec le framework Django. Il s'agit d'un moyen simple pour isoler les problèmes spécifiques à mod_python. La page Getting mod_python Working détaille cette procédure.
L'étape suivante serait d'éditer votre code de test et d'importer ajouter n'importe quel bout de code spécifique Django que vous utiliser -- vos vues, modèles, configuration d'url, configuration RSS, etc. Mettez ces bouts de code importer dans votre function de test au sein de votre handler et accédez-y avec votre navigateur. Si cela conduit à un crash, vous venez de confirmer que c'est le code Django importé qui pose problème. Réduisez progressivement la taille du code importé jusqu'à ce que le crash n'ait plus lieu afin de trouver le module qui pose problème. Plonger dans les modules et les modules importés xsdepuis ces premiers modules si nécessaire.