Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Django
  3. Création de site
Extrait - Django Développez vos applications web en Python (fonctionnalités essentielles et bonnes pratiques)
Extraits du livre
Django Développez vos applications web en Python (fonctionnalités essentielles et bonnes pratiques)
3 avis
Revenir à la page d'achat du livre

Création de site

Objectifs

Dans le chapitre précédent, les outils et l’infrastructure logicielle nécessaires à la création de site ont été mis en place. Ceci va permettre de poser les bases du projet.

Le choix du répertoire racine d’un site est libre, il n’y a aucune obligation en rapport avec Python ou Django. De même il n’y a pas à se placer sous la racine d’un serveur frontal (Apache, Nginx, etc.) et il vaut d’ailleurs mieux l’éviter pour ne pas s’exposer à un éventuel risque de visibilité du code à cause d’une faille de sécurité. Le présent exposé va être poursuivi avec une destination courte et expressive, choisie arbitrairement à D:\dj.

Création d’un projet

La mise en œuvre d’une infrastructure logicielle suppose le respect d’un cadre conventionnel de disposition des éléments, ou, dit en d’autres termes, mettre les choses là où l’infrastructure a prévu de les trouver. Plutôt que de tout devoir écrire soi-même, des assistants sont mis à disposition pour poser ce cadre initial, sur la base d’un gabarit, avec des valeurs par défaut supposées convenir dans la majorité des cas.

 Créez un nouveau répertoire pour héberger le projet :

D:\>md dj 

 Créez un nouveau projet, selon l’une ou l’autre façon :

D:\>\Python37\Scripts\django-admin startproject mysite dj 

Ou :

D:\>cd dj 
D:\dj>\Python37\Scripts\django-admin startproject mysite . 

Dans ce cas, notez bien la présence d’un caractère point isolé final.

Cette structure va être créée :

dj\ 
├─ manage.py 
└─ mysite\ 
  ├─ __init__.py 
  ├─ settings.py 
  ├─ urls.py 
  └─ wsgi.py 

La commande startproject a, d’une part, un paramètre obligatoire pour nommer le projet et, d’autre part, un paramètre optionnel pour citer un chemin de répertoire...

Premier lancement du site

Afin de se rassurer sur la bonne situation des actions menées jusqu’à présent, il est permis à ce stade de tenter un lancement du serveur de développement de Django.

 Passez la commande de lancement du serveur intégré :

D:\dj>py manage.py runserver 
Performing system checks... 
 
System check identified no issues (0 silenced). 
 
You have 15 unapplied migration(s). Your project may not work 
properly until you apply the migrations for app(s): admin, auth, 
contenttypes, sessions. 
Run 'python manage.py migrate' to apply them. 
<Mois JJ, AAAA - hh:mm:ss> 
Django version 2.1.5, using settings 'mysite.settings' 
Starting development server at http://127.0.0.1:8000/ 
Quit the server with CTRL-BREAK. 

On constate qu’à l’occasion de ce lancement, il est préalablement procédé à un balayage du projet, à la recherche d’erreurs usuelles. Il s’agit des mêmes contrôles que ceux de la commande check.

Le message d’avertissement à propos de migrations en attente d’application est attendu dans le contexte actuel. Il suffit de l’ignorer et il n’est pas nécessaire de passer la commande mentionnée.

Comme il est dit dans la sortie de la console et dans la documentation de la commande runserver, il ne s’agit aucunement d’un serveur utilisable pour un environnement de production.

C’est un outil dédié aux développeurs pour faciliter leur travail de conception, car il présente les avantages suivants :

  • Il est disponible sur la machine locale, immédiatement et sans effort. L’interface réseau et le port sont par défaut à 127.0.0.1 et 8000, mais il est possible de spécifier d’autres valeurs en arguments. Par exemple : manage.py runserver 192.168.0.10:8899 permet de servir aussi des requêtes provenant d’autres postes...

Création d’une première application

Maintenant que le cadre du projet est en place, il est possible d’y adjoindre une ou des applications. Le minimum est d’avoir une application. Pour un site très basique, on peut s’en contenter et y loger tout le code. Mais le plus souvent, il est préférable de concevoir une architecture modulaire, en cloisonnant les fonctionnalités par grandes familles, chacune donnant lieu à une application. Certaines applications vont émerger naturellement, par exemple parce qu’elles sont suffisamment génériques pour être employées dans d’autres projets, ou parce qu’elles fournissent une extension optionnelle de fonctionnalités.

Même si tout est estimé spécifique au projet et forme un ensemble technique apparemment compact et indissociable, une découpe présente néanmoins des avantages. Par exemple, pour des raisons de répartition de l’effort de développement puis de maintenance au sein d’une équipe, ou pour se ménager la possible substitution d’une technologie par une autre, éventuellement encore inconnue, quoique pressentie à ce stade.

A contrario, il faut se garder de l’excès inverse et tronçonner en de trop nombreuses applications. Certaines peuvent se révéler ridiculement petites ou la quantité peut devenir ingérable et donner une impression d’absence de maîtrise du sujet. On risque aussi de finir par ne plus savoir qui fait quoi et parfois on se retrouve à écrire ce qui l’a déjà été.

Une application offre des fonctionnalités et éventuellement fait appel aux fonctionnalités d’autres applications, d’où l’existence d’un réseau de dépendances. Dans ce réseau, la situation à éviter est d’aboutir à des boucles de dépendance, c’est-à-dire, par exemple, que l’application A a besoin de l’application B qui elle-même a besoin de l’application A.

Le raisonnement est le même si le chemin comporte plus de maillons. Ce schéma augmente le risque d’exposition au problème Python bien connu d’importation circulaire : pour importer...

Paramètres de configuration

Un embryon de site est désormais disponible, suffisant pour servir de terrain d’essais. Les capacités de configuration vont à présent être revues. Elles sont offertes via le fichier mysite\settings.py.

1. Configuration minimale

La documentation montre qu’il existe de l’ordre de 150 paramètres de configuration. Ces paramètres ont pratiquement tous une valeur par défaut, au cas où le fichier ne positionne pas un choix. Il existe cependant quelques rares exceptions pour lesquelles soit la valeur par défaut soit une combinaison avec la valeur d’un autre paramètre empêchent le démarrage du serveur.

SECRET_KEY : la chaîne vide par défaut doit être supplantée par une véritable valeur, censée être unique à un projet. Sinon, cela provoque l’erreur :

django.core.exceptions.ImproperlyConfigured: 
 The SECRET_KEY setting must  not be empty. 

ALLOWED_HOSTS : la liste vide par défaut n’est acceptée que si DEBUG est positionné à True, qui n’est pas sa valeur par défaut. Dans le cas contraire, il faudra fournir une liste valorisée, sinon le refus se traduit par le message :

CommandError: 
 You must set settings.ALLOWED_HOSTS if DEBUG is False. 

L’assistant de création de projets a fourni un socle minimal de départ, avec le positionnement de certains des paramètres à une valeur estimée usuelle.

Quelques valeurs sont pourtant déjà celles par défaut, mais cela peut se comprendre lorsque ce n’est pas la situation pour d’autres paramètres et que la réunion de ces paramètres forme un lot cohérent, à lire et interpréter ensemble.

Même lorsque le serveur a pu démarrer, on pourrait vite être confronté à des valeurs insuffisantes au moment de servir une requête. Par exemple :

AttributeError: 'Settings' object has no attribute 'ROOT_URLCONF' 

ROOT_URLCONF : en effet, sa valeur par défaut est non définie. Il ne faut pas y voir une erreur par omission, car une configuration de routage pourrait être adjointe dynamiquement à la requête par un intergiciel et aurait priorité....

Variations de configuration

Le site est amené à tourner selon différents contextes, par exemple : développement, tests, intégration, production. Ces contextes induisent inévitablement des paramètres de configuration adaptés précisément à chaque situation, ne serait-ce que pour la connexion à la base de données.

A priori, toutes les variations de paramétrage doivent être concentrées dans le fichier settings.py, puisque c’est son rôle. La question se ramène donc à viser des exemplaires différents de ce fichier ou à influencer son contenu.

Parmi les nombreuses façons de traiter le sujet, quelques-unes vont être exposées succinctement, réparties par famille.

Les techniques par désignation

Dans cette famille, l’objectif est d’aboutir à cibler précisément un contenu de fichier, final et complet, soit parce que c’est le seul, soit en suivant des critères de sélection.

La solution la plus rustique, à condition que la situation s’y prête, est simplement de désigner toujours un fichier de même nom, au même emplacement, mais dans lequel on a mis un contenu différent, spécifique à la machine hôte, qu’elle soit réelle ou virtuelle. Ceci suppose de dédier un environnement hôte à un contexte, de façon stable dans le temps.

La contrepartie de cette apparente simplicité est le conflit d’intégration avec un système de gestion de versions, puisqu’une même ressource devrait accueillir plusieurs contenus. On est alors obligé de se replier sur une gestion manuelle ou annexe, sujette à des risques d’oubli, d’écrasement, de mélange, etc. Encore d’autres difficultés apparaissent avec l’emploi d’outils d’automatisation pour les tests et les déploiements.

Pour remédier au souci de ressource unique, une solution consiste à associer à chaque environnement son fichier dédié. Le problème se déplace alors sur le moyen de déterminer, d’une part, l’environnement de lancement et, d’autre part, d’en déduire le bon fichier parmi une collection.

Les façons...

Création de l’application

Dans un premier temps, une structure minimale est mise en place, sachant que parfois il s’agit de contenus factices qui seront remplacés par la suite.

Le choix du nom de l’application n’est pas critique. Le terme messages est un candidat potentiel, mais il est préférable de l’éviter, car il est déjà employé par l’application intégrée django.contrib.messages. Pour rester dans le thème des communications, il est fait le choix du terme messenger.

Comme pour la première application, la nouvelle application sera placée dans le répertoire mysite.

 Créez une application :

D:\dj>cd mysite 
D:\dj\mysite>py ..\manage.py startapp messenger 

La situation doit maintenant être :

mysite\ 
├─ main\ 
└─ messenger\ 

 Sous messenger\, créez la hiérarchie de répertoires templates\messenger\.

Pourquoi créer à nouveau un sous-répertoire dans le répertoire des gabarits de l’application ? Parce que le moteur de gabarit, dans sa phase de recherche de fichier, va explorer les répertoires potentiels de chacune des applications et prendra la première correspondance trouvée. Or, il n’est pas rare que plusieurs applications emploient un même nom de fichier, usuel. C’est...

Outillage de mise au point

Comme annoncé à l’occasion de la référence à l’outil IDLE (cf. chapitre Installation - Après l’installation), maintenant qu’un projet est créé et disponible, il est intéressant de pouvoir faire quelques expérimentations sur ce projet, directement avec des instructions Python en ligne de commande. Ceci permet d’évaluer unitairement une portion de code, de lever un doute sur sa compréhension du comportement d’un élément, d’explorer en profondeur une structure de données, etc.

L’infrastructure logicielle propose justement pour cela une commande pour disposer d’un interpréteur, avec un environnement bien positionné, à l’image de celui du serveur de développement :

D:\dj>py manage.py shell 
Python 3.7.2 (tags/v3[...]) [MSC v.1916 64 bit (AMD64)] on win32 
Type "help", "copyright", "credits" or "license" for more i[...] 
(InteractiveConsole) 
>>> 

Cette console permet de facilement vérifier une vue, avant même qu’elle soit associée à une URL :

>>> from mysite.messenger import views 
>>>  
>>> views.index(None) 
<HttpResponse status_code=200, "text/html; charset=utf-8"> 
>>>...