Dans cette partie nous allons voir l’implémentation d’applications web, avec rendu de pages côté serveur.
Interface web et sites web - Contexte

Pour l’exemple du cours on utilise la page : https://example.org :
HTML
HTML (HyperText Markup Language) est le language utilisé pour structurer une page web et son contenu. Par exemple, le contenu peut être organisé sous forme de paragraphes, d’une liste à puces ou encore à l’aide d’images et de tableaux de données. C’est donc le contenu de base pour tout site web.
- A retenir Les fichiers
HTML
: Ils décrivent la structure logique d’une page web, définissent le contenu des pages. Ils s’écrivent a l’aide de balisesMarkup
de manière plutôt verbeuse.
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
Vous pouvez par exemple consulter ce code pen simple :
Introduction au HTML, avec explication des balises canon.
CSS
CSS (Cascading Style Sheets) est le language qui permet de styliser le contenu web. Sans CSS, un site n’a qu’une structure, mais pas de rendu visuel stylisé. Il est donc nécessaire de passer par la configuration de ces feuilles de style pour aboutir a un projet abouti côté Web.
- A retenir : Les fichiers
CSS
: fichiers de style, ils gèrent l’apparence des balises présentées.
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
- Exemple de codepen : https://codepen.io/webrav/pen/gMPppj
Javascript
JavaScript est un langage de programmation qui ajoute de l’interactivité aux sites web. Cela se produit dans les jeux, dans le comportement des réponses lorsque des boutons sont pressés, lors de la saisie de données dans des formulaires, avec des styles dynamiques, des animations, etc. Il permet de modifier le DOM, qui est le contexte rendu objet d’un site.
- A retenir : Les fichiers
javascript
: éléments de scripts du site, permettent de réaliser des actions sur des éléments Html ou css.
Exemple avec un bouton qui affiche un nombre aléatoire entre 0 et 1 :
<button id="button"type="button">Affichage d'un nombre aléatoire</button>
<div id="affichage"></div>
document.getElementById("button").onclick = function() {
document.getElementById("affichage").innerHTML = Math.random();
};
Un codepen simple : https://codepen.io/rcyou/pen/QEObEZ
Un codepen bien plus fourni : Une petite application statique qui va chercher des informations sur un pokemon avec une requête http en javascript : https://codepen.io/mikemilio/pen/poXOywy
Templating
Ce qui va nous intéresser aujourd’hui c’est d’effectuer un rendu des pages côté serveur et donc de limiter la logique au maximum à des traitements internes a notre application : on parle alors de Server Side Rendering.
Cela a différents avantages / inconvénients : notamment un meilleur contrôle des requêtes ou également la rapidité dans le cas d’un cache applicatif.
Nous allons donc ici nous intéresser au contenu des pages rendues et donc aux fichiers html
des sites, qu’on va vouloir templatiser et renseigner en fonction de divers informations qu’on aura a l’intérieur de nos programmes.
Un petit historique : La plupart des applications web “anciennes” sont en PHP + JS + HTML + CSS pour utiliser la flexibilité du php pour la construction de pages templatisées
.
En python des applications du même type peuvent être construites avec le framework Django mais également a l’aide de FASTAPI en faisant renvoyer des pages HTML templatisées.
Templating Engine : Présentation de Jinja2

Un templating engine (ou moteur de templating) est un outil utilisé pour générer dynamiquement du contenu, généralement du HTML, en combinant des données et un modèle de mise en page (template). On s’en sert en général pour la génération de pages HTML
côté serveur, en injectant les résultats de traitements applicatifs dans des pages.
NB: Cela permet de séparer la logique “service” de la logique vue (CF cours 1)
Jinja2 est un moteur de template pour Python, largement utilisé dans les frameworks web comme Flask. Il permet de générer du HTML dynamique en utilisant des variables, des boucles et des conditions. Il est également utilisé dans une myriade d’outils d’où la présentation .
Voyez plutôt ce template, qui sert pour configurer un fichier a envoyer par mail.
<html>
<body>
<h1>Bonjour {{ user_name }},</h1>
<p>Merci de vous être inscrit sur notre plateforme.</p>
<p>Votre email : {{ user_email }}</p>
{% if is_admin %}
<p><strong>Vous avez des privilèges administrateurs.</strong></p>
{% endif %}
<p>Cordialement,</p>
<p>L'équipe du support du site XXXX</p>
</body>
</html>
- Jinja2 utilise des doubles accolades
{{ }}
pour insérer des variables dynamiques dans un template. Ces variables sont remplacées lors du rendu du template. - Jinja2 prend en charge les structures de contrôle comme les conditions (
if
), les boucles (for
) et les filtres (upper
,lower
,length
etc.). Ces structures permettent d’adapter le contenu rendu en fonction des données.
Un peu de code
with open(os.path.join(chemin_script,"template.html"),"r",encoding="utf-8") as fichier_template:
contenu_fichier_template = fichier_template.read()
template_rempli_non_admin=template.render(
user_name=USER_NAME,user_email=USER_EMAIL,is_admin=False
)
Avec les valeurs user_name = "antoine"
, user_email = "antoinebrunetti@gmail.com"
et is_admin = True
<html>
<body>
<h1>Bonjour antoine,</h1>
<p>Merci de vous être inscrit sur notre plateforme.</p>
<p>Votre email : antoinebrunetti@gmail.com</p>
<p><strong>Vous avez des privilèges administrateurs.</strong></p>
<p>Cordialement,</p>
<p>L'équipe de support</p>
</body>
</html>
Documentation officielle https://jinja.palletsprojects.com/en/stable/intro/
Accédez a l’exemple conçu pour le cours et executez le : https://github.com/conception-logicielle-ensai/exemples-cours/tree/main/cours-4/web-templating
Server Side Rendering (SSR) : Exemple avec FastAPI

Le rendu côté serveur (Server Side Rendering, SSR) est une architecture où les pages HTML sont générées sur le serveur avant d’être envoyées au navigateur. Cela permet d’améliorer le temps de chargement initial.
Remarque on utilise aussi souvent cela pour le référencement (SEO), en particulier pour les moteurs de recherche qui ont du mal à indexer le contenu rendu côté client.
Principe
Comme vu précédemment, FastAPI
est un framework web rapide pour Python, il permet de mettre a disposition du code via HTTP.
En s’appuyant sur du templating Jinja
de pages HTML
on peut donc dynamiquement répondre a des requêtes utilisateurs en fabriquant les pages HTML côté serveur.
Mise en oeuvre
Nativement, après l’installation de jinja2, fastapi permet l’usage des templates précédemment présentés :
from fastapi.templating import Jinja2Templates
.
Il suffit d’organiser le code projet ainsi :
projet/
│-- templates/
│ │-- index.html
│-- main.py # ou un autre module main
Et d’importer les templates ainsi :
from fastapi.templating import Jinja2Templates
templates = Jinja2Templates(directory="templates")
Exemple de projet simple : lien vers l’exemple-minimal
Il existe beaucoup d’éléments de configuration, inspirez vous de la documentation et des exemples de code.
La documentation est ici https://fastapi.tiangolo.com/advanced/templates/
Un exemple plus concret pour vous inspirer pour vos projets : https://github.com/conception-logicielle-ensai/exemples-cours/tree/main/cours-4/fastapi-web-templating/app
Django : Le framework “tout en un”
Django est le framework historique de développement d’applications avec rendu de template html côté serveur. Il propose une myriade de fonctionnalités qui ont la particularité d’être dans une approche opt-in
, on peut activer ou desactiver une fonctionnalité par de la configuration applicative.
Il propose une architecture interne implémentant le pattern MTV (Model-Template-View)
:
- Modèle (Model) : DAO (Data Access Object) - des objets mappés en base de données accessibles via l’ORM interne a django.
Pour info un ORM, Object Relational Mapping, est un outil créant un couplage entre un modèle de classes et un modèle de données en base de données, il implémente différentes méthodes pour récupérer les objets
- Vue (View) : Définition de la logique métier et permet de renvoyer une réponse HTTP adaptée a une requête.
Il implémente également un
Middleware
: composant interceptant les requêtes et leur appliquant des propriétés => Authentification, session, redirection..
Configuration
Dans un projet Django, la configuration globale se fait a l’interieur même du projet, ou par variables d’environnements :
https://docs.djangoproject.com/fr/5.1/topics/settings/#designating-the-settings
Documentation externe:
Pour démarrer si vous partez sur cette solution :
Exemple simple
Il s’agit d’un projet mis en place assez simplement, inspirez vous du README Suivez un des tutoriels
https://openclassrooms.com/fr/courses/7172076-debutez-avec-le-framework-django
https://docs.djangoproject.com/en/5.1/intro/
Documentation overview: https://docs.djangoproject.com/en/5.1/intro/overview/
Exemple “avancé” : https://github.com/conception-logicielle-ensai/exemples-cours/tree/main/cours-4/django/app le README est également constitué a façon pour vous permettre de démarrer.
Django design philosophies : voir https://docs.djangoproject.com/fr/5.1/misc/design-philosophies/
Websockets
Qu’est-ce qu’un WebSocket ?
Un WebSocket est un protocole de communication bidirectionnel qui permet une interaction en temps réel entre un client et un serveur.
=> Contrairement au protocole HTTP, qui fonctionne sur un modèle requête-réponse, WebSocket établit une connexion persistante où les deux parties peuvent envoyer et recevoir des messages à tout moment.
Ce protocole est particulièrement utile pour les applications nécessitant des mises à jour en temps réel, comme les chats en ligne, les jeux multijoueurs ou les notifications instantanées.
Un peu de TCP
WebSocket fonctionne au-dessus de TCP (Transmission Control Protocol), qui est un protocole de transport garantissant la livraison fiable des données. Lorsqu’une connexion WebSocket est établie, elle commence par une requête HTTP spéciale appelée “handshake”. Une fois le handshake réussi, la connexion passe en mode WebSocket et permet l’échange de données en temps réel.
Les acteurs dans une architecture WebSocket
Il existe deux types d’acteurs principaux dans une architecture WebSocket : les clients et les serveurs.
Le client est l’entité qui initie la connexion WebSocket en envoyant une requête au serveur. Une fois la connexion établie, il peut envoyer et recevoir des messages en temps réel.
Le serveur écoute les connexions entrantes des clients, gère les sessions et transmet les messages aux destinataires appropriés. Il est responsable de maintenir la connexion active et de relayer les messages entre les différents clients.
Ces deux composants travaillent ensemble pour offrir une communication fluide et en temps réel, essentielle pour de nombreuses applications modernes.
Exemple d’implémentation
L’exemple ici présenté correspond a l’exemple du cours : https://github.com/conception-logicielle-ensai/exemples-cours/tree/main/cours-4/websocket
On repose sur la librairie légère websockets
et la librairie asyncio
par practicité.
- Côté serveur
import asyncio
import websockets
# Ensemble pour stocker les connexions actives
connected_clients = set()
async def broadcast(message):
for client in connected_clients:
await client.send(message)
async def handle_client(websocket):
# Ajoute le client connecté à l'ensemble
connected_clients.add(websocket)
print(f"Client connecté. Total clients : {len(connected_clients)}")
try:
async for message in websocket:
print(f"Message reçu : {message}")
await broadcast(f"Message d'un client : {message}")
except websockets.exceptions.ConnectionClosed:
print("Client déconnecté.")
finally:
# Retire le client de l'ensemble à sa déconnexion
connected_clients.remove(websocket)
print(f"Client déconnecté. Total clients : {len(connected_clients)}")
async def main():
async with websockets.serve(handle_client, "localhost", 8765):
print("Serveur WebSocket démarré sur ws://localhost:8765")
await asyncio.Future() # Garde le serveur actif
if __name__ == "__main__":
asyncio.run(main())
On démarre un serveur accesible sur le port 8765
- Côté client
import asyncio
import websockets
async def communicate():
uri = "ws://localhost:8765"
async with websockets.connect(uri) as websocket:
message = "Hello, WebSocket Server!"
print(f"Envoi : {message}")
await websocket.send(message)
response = await websocket.recv()
print(f"Réponse du serveur : {response}")
if __name__ == "__main__":
asyncio.run(communicate())
On s’y connecte directement puis on broadcast des messages
- Il est également possible de gérer une session directement dans le navigateur via l’usage du
Javascript
.
const socket = new WebSocket("ws://localhost:8765");
socket.onopen = function(event) {
console.log("Connexion établie avec le serveur WebSocket");
};
socket.onmessage = function(event) {
console.log("Message reçu du serveur :", event.data);
document.getElementById("messages").innerHTML += `<p>${event.data}</p>`;
};
socket.onclose = function(event) {
console.log("Connexion fermée");
};
function sendMessage() {
const message = "Hello depuis le client javascript !";
console.log("Envoi :", message);
socket.send(message);
}
Travaux pratiques
Mettez en place une première architecture dans vos projets :
- Déterminez la solution privilégiée pour votre projet a partir de ce qui a été présenté
- Renseignez pour la séance courante les technologies https://docs.google.com/spreadsheets/d/1VlfoNcXhhJ2tr3OVYCIBmzutdzA56usssL11lCISgIg/edit?usp=sharing
- En se réunissant par groupes, travaillez sur vos projets et pinguez nous quand vous avez besoin de nous : (colonne 4 https://docs.google.com/spreadsheets/d/1VlfoNcXhhJ2tr3OVYCIBmzutdzA56usssL11lCISgIg/edit?usp=sharing)