CentraleSupélecDépartement informatique
Gâteau du Glouton
3 rue Joliot-Curie
F-91192 Gif-sur-Yvette cedex
Tuto Django

1 - Mise en route

Il s'agit d'installer django. Il s'agit d'un paquet python disponible dans la bibliothèque accessible par pip.

  • En ligne de commande:
pip install django
  • Ou à travers votre IDE... Mais là, vous savez en principe comment elle marche.

Vous pouvez tester l'installation en lançant sur la ligne de commande:

  • la commande
django-admin --version

Cela devrait vous afficher... le numéro de version. Si ce n'est pas le cas, il y a un problème.

  • la commande
python -m django --version

Encore une fois, cela ne devrait pas donner de message d'erreur et vous donner un numéro de version...

Si cela fonctionne, nous allons maintenant fabriquer un petit serveur qui délivre du contenu. Le reste de ce tutoriel s'inspire du tuto officiel disponible à l'adresse https://docs.djangoproject.com/en/2.2/intro/tutorial01/.

2 - Fabriquons un serveur qui ne fait rien.

Un serveur Django est un ensemble de fichiers python à l'intérieur d'une arborescence de fichiers spécifique au serveur: un dossier source contenant un ensemble de sous-dossiers appelés des "applications".

Dans le cadre de ce tutoriel, nous allons resté au plus simple. Nous allons nous contenter de créer un serveur monolithique.

  • Avec la ligne de commande, placez vous dans votre dossier personnel
cd un-chemin-vers-votre-repertoire-personnel
  • entrez la commande
django-admin startproject mysite

Cela devrait avoir produit un dossier mysite dans le répertoire courant avec l'arborescence de fichiers suivante:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

Le tuto décrit l'ensemble de fichiers comme suit:

  • The outer mysite/ root directory is just a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like.
  • manage.py: A command-line utility that lets you interact with this Django project in various ways. You can read all the details about manage.py in django-admin and manage.py
  • The inner mysite/ directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it (e.g. mysite.urls).
  • mysite/__init__.py: An empty file that tells Python that this directory should be considered a Python package. If you’re a Python beginner, read more about packages in the official Python docs.
  • mysite/settings.py: Settings/configuration for this Django project. Django settings will tell you all about how settings work.
  • mysite/urls.py: The URL declarations for this Django project; a “table of contents” of your Django-powered site. You can read more about URLs in URL dispatcher.
  • mysite/wsgi.py: An entry-point for WSGI-compatible web servers to serve your project. See How to deploy with WSGI for more details.
  • Comme déjà dit plus haut, nous allons dans notre cas rester au plus simple: nous ne ferons pas d'applications particulières, et nous ne ferons pas d'autres packages.
  • Vérifions que le serveur fonctionne. Avec la ligne de commande:
cd mysite
python manage.py runserver

Vous devriez voir la chose suivante apparaitre:

Performing system checks...

System check identified no issues (0 silenced).

You have unapplied migrations; your app may not work properly until they are applied.
Run 'python manage.py migrate' to apply them.

April 16, 2019 - 15:50:53
Django version 2.2, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Pour les besoins de ce tuto vous pouvez ignorer le warning. Si vous voulez en savoir plus, je vous invite à regarder le tuto officiel sur le site de Django.

  • Le serveur tourne ! Vous pouvez maintenant aller à l'adresse http://127.0.0.1:8000/ avec un navigateur pour voir...
  • En principe, si vous modifiez les fichiers python, le serveur se relance tout seul (vous devriez le voir sur la console). Sinon, il faut le relancer à la main...

3 - Jouons avec les chemins d'accès

Un serveur Django va essentiellement associer un chemin d'accès à une fonction python qui se doit de fabriquer une réponse. Les chemins d'accès sont placés dans le fichier urls.py. Si vous l'ouvrez, vous devriez voir le tableau

urlpatterns = [
    path('admin/', admin.site.urls)
]

On a donc pour l'instant qu'un seul chemin par défaut qui va vers l'adresse http://127.0.0.1:8000/admin. Si vous vous y rendez, vous pourrez en deéduire que Django vient avec des outils clé-en-main pour gérer un certain nombre de chose en rapport avec les privilèges. Il s'agit d'un sujet avancé sur lequel je ne suis pas spécialiste: je vous invite à aller voir le tuto officiel, qui vous donnera quelques explications et des pointeurs. Mais pour les besoins d'aujourd'hui, nous n'en aurons pas besoin.

Dans tous les cas, le tableau urlpatterns associe des chemins à des fonctions (qu'il faut donc importer bien sûr).

Chemin d'accès simple

On peut par exemple faire la chose suivante:

  • créez un fichier views.py dans le même dossier que urls.py et placez-y le code suivant:
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the root of the server.")

et mettez à jour urls.py avec

from . import views

urlpatterns = [
    path('', views.index)
]
  • on associe donc au chemin vide (c'est à dire http://127.0.0.1:8000) l'action d'une fonction qui s'appelle index. Celle-ci génére une réponse HTTP pour le client avec du texte.
  • on peut faire une fonction active qui ne rend pas toujours le même texte. Par exemple:
    • Ajoutez dans views.py:
counter = 0

def inc(request):
    global counter
    counter = counter + 1
    return HttpResponse("The counter is now set to " + str(counter))
  • Ajoutez dans urls.py le chemin
    path('counter', views.inc),    

Chemin d'accès dynamique

Il est possible de paramétrer le comportement de la fonction qui génère la réponse HTTP en fonction du type de chemin d'accès. Par exemple:

  • Ajoutez dans urls.py le chemin
    path('dyn/<int:unevaleur>/<int:encoreunevaleur>', views.desvaleurs),    
  • Ajoutez dans views.py la fonction
def desvaleurs(request, unevaleur, encoreunevaleur):
    return HttpResponse("I got the values " + str(unevaleur) + " and " + str(encoreunevaleur))

Accès aux arguments

Une adresse web peut contenir un suffixe sous la forme ?key1=val1&key2=val2&.... Ce suffixe ne fait pas partie du chemin d'accès : il s'agit simplement d'une table d'association passée au serveur. Avec Django, cette table d'association est rangée dans l'argument request.GET. Par exemple, modifiez la fonction index de views.py pour le code suivant.

from django.http import HttpResponse, HttpRequest

def index(request):
    response = HttpResponse()
    for key in request.GET:
        response.write("The key " + key + " is associated with the value " + request.GET[key] + "<br>")
    return response

4 - Le format de réponse HTTP

Pour l'instant, nous n'avons pas analysé en détail le format de la réponse HTTP. Par défaut, HttpResponse avec un argument de type string renvoie fait une réponse de type HTML. C'est paramétrable, avec un argument.

  • Par exemple, si on veut délivrer non pas une page HTML mais du JSON par exemple, on peut faire la chose suivante:
from django.http import HttpResponse, HttpRequest

def index(request):
    response = HttpResponse("[1,2,3]", content_type="application/json")
    return response

La chaine de caractère sera émise avec le type MIME correspondant à JSON, et le navigateur comprendra qu'il s'agit d'une resource JSON. Essayez !

  • On peut aussi transformer un objet python en JSON automatiquement en utilisant la classe JsonResponse. Par exemple, on pourrait faire
from django.http import JsonResponse, HttpRequest, HttpResponse

def index(request):
    monobjet = {'key1' : 1, 'key2' : 'abc', 'key3' : [1,2,3]}
    response = JsonResponse(monobjet)
    return response
  • Notez l'import de JsonResponse.
  • Essayez pour voir !

5 - Un petit service web

Essayez de réaliser un tout petit service web qui permet de stocker des clés et des valeurs au niveau serveur. On veut deux types de chemins:

Par exemple, on ajoutera dans le fichier urls.py les lignes

    path('/get', views.myget),    
    path('/set', views.myset),    

et dans le fichier views.py on ajoutera deux fonctions


tableAssoc = {}

def myget(request):
    # Lit la requète et répond soit tableAssoc soit une valeur de tableAssoc

def myset(request):
    # Lit la requète, met à jour tableAssoc et renvoie une réponse HTML du style
    # "j'ai associé la valeur XXX à la clé YYY"

Remplissez le corps des fonctions, et essayez pour voir !

6 - Accès à des fichiers statiques

Outre la possibilité d'être utilisé comme service web délivrant du contenu, comme au dessus, un serveur internet délivre habituellement simplement du contenu statique: à une resource est associé un fichier sur le serveur. Le problème est de réussir à faire cela de façon sécurisée. Dans notre cas, nous allons faire quelque chose de simple QU'IL NE FAUT PAS FAIRE EN PRODUCTION. Lisez la doc si vous êtes curieux de comment faire quelque chose de propre...

Dans le cadre de notre tutoriel, il devrait suffire de faire les choses suivantes:

  • Créez dans le sous-répertoire "mysite/mysite/" un répertoire "static".
  • Placez-y un fichier a.txt dans lequel vous mettez le texte HELLO
  • Dans le fichier settings.py, vérifiez que vous avez les choses suivantes (ajoutez-les le cas échéant):
    • Une variable définie comme
STATIC_URL = '/static/'
  • Dans le tableau INSTALLED_APPS, les chaines de caractères suivantes:
    'django.contrib.staticfiles'

et

    'mysite'
  • Relancez votre serveur et essayez d'accèder à l'adresse http://127.0.0.1:8000/static/a.txt : le texte du fichier doit s'afficher.
  • À la place de ce fichier, vous pouvez mettre des fichiers variés: images, css, javascript, html, json, xml, etc... et Django devrait les délivrer avec le type MIME qui va bien.

Exercice

Réalisez une (toute) petite application web complète, qui contient

  • une page HTML statique augmente.html
<!DOCTYPE html>
<html>
<head>
  <title>Augmente</title>
  <script type="text/javascript" src="augmente.js">
</head>
<body>
  <p id="elementAChanger" onclick="mafonction()">ICI</p>
</body>
</html>
  • Un fichier javascript statique augmente.js qui contient la définition de la fonction mafonction() faisant un appel AJAX à un service web /inc
  • Le service web /inc (donc défini par un chemin et une fonction python) qui
    • incrémente un compteur coté serveur
    • réponds la valeur du compteur sous la forme d'une resource JSON
  • Donc lorsqu'on charge la page HTML et qu'on clique sur le paragraphe, la valeur du compteur doit s'afficher, et augmenter à chaque clic.

7 - Notion de gabarit ("template", en anglais)

Dans certains cas, on souhaite pouvoir générer ou compléter automatiquement un document (HTML par exemple) au niveau serveur, sans passer par un appel AJAX pour le modifier au niveau du client. Django permet de faire cela de façon simple, en utilisant la notion de gabarits ("templates" en anglais). Les templates sont des fichiers placées par défaut dans un dossier templates (notez le "s") au même niveau que le dossier static.

Afin de tester le comportement du serveur en présence d'un template, réalisez les opérations suivantes:

  • Créez un fichier test.html dans le dossier templates que vous aurez préalablement créé.
  • Placez-y le texte:
<html>
  <body>
<ul>
    {% for name in listeDeNoms %}
        <li>{{ name }}</li>
    {% endfor %}
</ul>
  </body>
</html>
  • Dans le fichier views.py, changez la fonction index par
from django.template import loader

def index(request):
    template = loader.get_template('test.html')
    context = {
        'listeDeNoms' : ['Bob', 'Alice', 'Gustav']
    }
    return HttpResponse(template.render(context, request))
  • Relancez le serveur le cas échéant et rendez-vous sur la page http://127.0.0.1:8000.
  • Modifiez la liste et rechargez la page, pour voir.

Vous trouverez la doc ici: https://docs.djangoproject.com/en/2.2/topics/templates/

Exercice

Reprenez l'exercice proposé en section 5 et réalisez une petite interface html pour présenter les résultats.

Conclusion

À ce stade, vous devriez pouvoir faire une application web à peu près complète: votre application peut stocker des données coté serveur, proposer une interface (API) pour les modifier ou les consulter, délivrer des fichiers statiques, et même d'en générer dynamiquement avec l'utilisation de templates. En complement d'AJAX, il est à priori possible de faire faire ce que l'on veut à notre application web.