Chapitre 16: Intégration d’applications et de bases de données existantes
Django est bien placé pour ce que qui s’appelle de développement à partir d’une friche - autrement dit, démarrer les projects à partir de rien, comme si vous alliez construire un bâtiment sur un terrain d’herbe fraîche. Mais en dépit du fait que Django favorise les projets partant de zéro, il est possible d’intégrer au framework des bases de données existantes et des applications. Ce chapitre explique quelques stratégies d’intégration.
Intégrer une bases de données existante
La couche base de données de Django génère des schémas SQL à partir de code Python - alors qu’avec une base de données existante, vous avez déjà les schémas SQL. Dans pareil cas, vous devrez créer des modèles pour vos tables existantes en base de données. Pour ce faire, Django est livré avec un outil capable de générer le code d’un modèle en lisant la disposition des tables de la base de données. Cet outils se nomme inspectdb, et vous pouvez l’appelé en exécutant la commande manage.py inspectdb.
Utilisation de inspectdb
L’utilitaire inspectdb introspecte la base de données précisée par votre fichier de paramètres, détermine une représentation de modèle Django pour chacune de vos tables, et affiche le code Python du modèle sur la sortie standard.
Voici une étude d’un processus typique d’intégration d’une base de données existante à partir de zéro. Les seules postulats sont que Django est installé et que vous avez une base de données existante.
Créez un projet Django grâce à la commande django-admin.py startproject monsite (où monsite est le nom de votre projet). Nous utiliserons monsite comme nom de projet pour cet exemple.
Éditez le fichier des paramètres de ce projet, mysite/settings.py, pour préciser à Django les paramètres de connexion de votre base de données ainsi que le nom de celle-ci. Renseignez en particulier les paramètres DATABASE_NAME, DATABASE_ENGINE, DATABASE_USER, DATABASE_PASSWORD, DATABASE_HOST, et DATABASE_PORT. (Notee que certains de ces paramètres sont optionnels. Référez vous au chapitre 5 pour plus d’information).
Créez une application Django au sein de votre projet en lançant python monsite/manage.py startapp monappli (où monappli est le nom de votre application). Nous utiliserons ici monappli comme nom d’application.
Lancez la commande python monsite/manage.py inspectdb. Cette commande examinera les tables présentes dans la base de données DATABASE_NAME et affichera la classe de modèle générée pour chacune des tables. Jetez un oeil à la sortie pour vous faire une idée de ce que inspectdb peut faire.
Enregistrez la sortie dans le fichier models.py au sein de votre application en utilisant la redirection de sortie standard du shell:
python monsite/manage.py inspectdb > monsite/monappli/models.py
Éditez le fichier monsite/monappli/models.py pour nettoyer le modèle généré et faire les personnalisations nécessaires. Nous donnerons quelques indices sur le sujet dans une prochaine section.
Nettoyer les modèles générés
Comme vous pouviez vous y attendre, l’introspection de la base de données n’est pas parfaite, et vous aurez besoin de faire une légère toilette au code du modèle résultant. Voici quelques pistes pour gérer les modèles générés:
Chaque table de la base de données est convertie en une classe de modèle (c’est à dire qu’il y a une relation un-à-un entre les tables de la base de données et les classes de modèle). Cela signifie que vous devrez refactoriser vos modèles pour toute les tables jointes par une relation plusieurs-à-plusieurs en objets ManyToManyField.
Chaque modèle généré possède un attribut pour chaque champs, y compris les champs id de clef primaire. Cependant, souvenez-vous que Django ajoute automatiquement un champ id de clef primaire si un modèle ne possède pas de clef primaire. Ainsi, vous pourrez supprimer toutes les lignes qui ressemblent à ceci:
id = models.IntegerField(primary_key=True)
Ces lignes ne sont pas seulement redondantes, elles peuvent aussi causer des problèmes si votre application ajoute de nouveaux enregistrements à ces tables. La commande inspectdb ne peut pas détecter si un champ est auto-incrémenté, aussi devez vous modifier cela au profit d’un AutoField, si nécessaire.
Chaque type de champ (par exemple, CharField, DateField) est déterminé en examinant le type de la colonne dans la base de données (par exemple, VARCHAR, DATE). Si inspectdb ne peut mettre en correspondance le type de colonne avec un modèle du type de champ, elle utilisera TextField et insérera dans le modèle généré le commentaire Python 'This field type is a guess.' (ndt: ce type de champ est une supposition) juste à côté du champ. Examinez bien cela, et modifiez le type de champ en conséquence sinécessaire.
Si un champ de votre base de donnée n’a pas d’équivalent pertinant sous Django, vous pouvez sans danger le laisser de côté. La couche du modèle Django n’est pas indispensable pour inclure chaque champ dans votre ou vos table(s).
Si une colonne de la base de données est un mot réservé par Python (tel que pass, class, ou for), inspectdb ajoutera '_field' au nom de l’attribut et fixera l’attribut db_column selon le nom réel du champ (par exemple pass, class, ou for).
Par exemple, si une table possède une colonne INT appelée for, le modèle généré aura un champ semblable à ceci:
for_field = models.IntegerField(db_column='for')
inspectdb insérera le commentaire Python 'Field renamed because it was a Python reserved word.' (ndt: Champ renommé parce qu’il s’agissait d’un mot réservé par Python) à côté du champ.
Si votre base de données contient des tables se référant à d’autres tables (comme le font la plupart des bases de données), vous pourriez avoir besoin de réarranger l’ordre des modèles générés de façon à ce que les modèles se référant à d’autres modèles soient correctement ordonnés. Par exemple, si le modèle Book à une ForeignKey vers le modèle Author, le modèle Author doit être défini avant le modèle Book. Si vous devez créer une relation vers un modèle qui n’a pas encore été défini, vous pouvez utilisez le nom du modèle, plutôt que l’objet modèle lui-même.
inspectdb détecte les clefs primaires pour PostgreSQL, MySQL, et SQLite. Ceci étant, il insert primary_key=True là où c’est approprié. Pour les autres base de données, vous devrez insérer un primary_key=True pour au moin un champ de chaque modèle, puisque les modèles Django sont requis pour obtenir un champ primary_key=True.
La détection des clef étrangères fonctionne uniquement avec PostgreSQL et avec certains types de tables MySQL. dans les autres cas, les champs de clef étrangère seront générés sous la forme de IntegerField, si l’on considère que la colonne de clef étrangère était une colonne de type INT.
Intégration d’un système d’identification
Il est possible d’intégrer à Django un système d’identification existant - une autre source de noms d’utilisateur et de mots de passe ou bien de méthodes d’identification.
Par exemple, votre compagnie à peut être déjà configuré un LDAP qui stocke les noms d’utilisateur et les mots de passe de tous les employés. Cela pourrait être ennuyeux à la fois pour l’administrateur et pour les utilisateurs eux-même si les comptes dans LDAP et dans les applications basées sur Django étaient séparés.
Pour gérer des situations comme celle-ci, le système d’identification de Django vous laisse brancher d’autres sources d’identification. Vous pouvez outrepasser le système reposant sur une base de donnée, par défaut sous Django, ou utiliser le système par défaut en tandem avec d’autres systèmes.
Préciser les moteurs d’identification
En coulisses, Django maintient une liste de «moteurs d’identification» qui contrôlent l’identification. Lorsque quelqu’un appelle django.contrib.auth.authenticate() (comme décrit au chapitre 12), Django tente de l’identifier parmis tous ses moteurs d’identification. Si la première méthode d’identification échoue, Django tente la seconde, et ainsi de suite, jusqu’à ce que tous les moteurs aient été essayés.
La liste des moteurs d’identification à utiliser est précisée dans le paramètre AUTHENTICATION_BACKENDS. Ce doit être un tuple de nom de chemin Python qui pointe sur les classes Python qui savent comment assurer l’identification. Ces classes peuvent être n’importe où sur votre chemin Python.
Par défaut, AUTHENTICATION_BACKENDS est paramétré comme suit:
('django.contrib.auth.backends.ModelBackend',)
Il s’agit du système d’identification basique qui contrôle la base de données des utilisateurs sous Django.
L’ordre des AUTHENTICATION_BACKENDS importe, ainsi donc si le même nom d’utilisateur et le même mot de passe sont valides dans de multiples moteurs, Django arrêtera le traitement à la première correspondance positive.
Écrire un moteur d’identification
Un moteur d’identification est une classe qui implémente deux méthodes: get_user(id) et authenticate(**credentials).
La méthode get_user prends un id - qui peut être le nom d’un utilisateur, un ID de base de données, ou autre - et renvoie un objet User.
La méthode authenticate prends «credentials» pour arguments mot-clef. La pluaprt du temps il ressemble à ceci:
class MyBackend(object):
def authenticate(self, username=None, password=None):
# Check the username/password and return a User.
Mais il peut aussi identifié un symbole, comme ici:
class MyBackend(object):
def authenticate(self, token=None):
# Check the token and return a User.
Dans les deux cas, authenticate doit vérifier les «credentials» qu’il a, et doit renvoyer un objet User qui correspond à ces «credentials», si ceux-ci sont valides. S’ils ne le sont pas, il doit renvoyer None.
Le système d’administration de Django est intimement couplé à l’objet User adossé à la base de donnée propre à Django et décrit au chapitre 12. La meilleure façon de gérer ceci consiste à créer un objet User pour chaque utilisateur qui existe dans votre moteur (par exemple, dans votre répertoire LDAP, dans votre base de données SQL, etc.). Vous pouvez soit écrire un script pour faire ceci à l’avance, soit le faire grâce à votre méthode authenticate lorsque un utilisateur se connecte pour la première fois.
Voici un exemple de moteur qui identifie un nom d’utilisateur et un mot de passe par comparaison avec une variable de votre fichier settings.py et crée un objet User la première fois qu’un utilisateur s’identifie:
from django.conf import settings
from django.contrib.auth.models import User, check_password
class SettingsBackend(object):
"""
Authenticate against the settings ADMIN_LOGIN and
ADMIN_PASSWORD.
Use the login name, and a hash of the password. For example:
ADMIN_LOGIN = 'admin'
ADMIN_PASSWORD =
'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
"""
def authenticate(self, username=None, password=None):
login_valid = (settings.ADMIN_LOGIN == username)
pwd_valid = check_password(password,
settings.ADMIN_PASSWORD)
if login_valid and pwd_valid:
try:
user =
User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. Note that we can
set password
# to anything, because it won't be
checked; the password
# from settings.py will.
user = User(username=username,
password='get from settings.py')
user.is_staff = True
user.is_superuser = True
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Intégration des applications web existantes
Il est possible de lancer une application Django sur le même serveur web en tant qu’application propulsée par une autre technologie. La façon la plus directe de faire cela est d’utiliser le fichier de configuration d’Apache, httpd.conf, pour déléguer différents patrons d’URL à différentes technologies. Notez que le chapitre 20 couvre le déploiement de Django avec Apache/mod_python, il est donc préférable de lire ce chapitre avant de tenter cette intégration).
La clef est que Django sera activé pour un patron d’URL particulier seulement si votre fichier httpd.conf l’indique. Le déploiement par défaut expliqué au chapitre 20 considère que vous voulez que Django propulse toutes les pages d’un domaine particulier:
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>
Ici, la ligne <Location "/"> signifie «gère chaque URL, commençant à la racine», avec Django.
Il est parfaitement correct de limiter cette directive <Location> à une certaine arborescence de répertoire. Par exemple, admettons que vous ayez une application PHP existante qui propulse la plupart des pages d’un domaine et que vous vouliez installer un site d’administratin de Django à l’adresse /admin/ sans désorganiser le code PHP. Pour ce faire, placez simplement la directive <Location> à /admin/:
<Location "/admin/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>
Avec ceci en place, seuls les URLs qui commencent par /admin/ activerons Django. Tout autre page utilisera n’importe quelle infrastructure déjà existante.
Notez qu’attacher Django à un URL qualifié ( tel que /admin/ dans l’exemple de cette section) n’affecte pas l’analyse de l’URL par Django. Django travail à partir de l’URL absolu (par exemple, /admin/people/person/add/), et non pas d’une version «vidée» de l’URL (par exemple, /people/person/add/). Cela signifie que votre URLconf racine doit inclure la partie /admin/ initiale.
Et ensuite ?
En parlant du site d’administration de Django et en pliant le framework afin qu’il s’adapte aux besoins existants, une autre tâche courante consiste à personnaliser le site d’administration de Django. Le chapitre suivant s’intéresse à ces personnalisations.
Dernière modification: 2008-08-05 15:16:28.332339