566 lines
22 KiB
Markdown
566 lines
22 KiB
Markdown
---
|
||
title: URLs dans Django
|
||
author: Steve Kossouho
|
||
---
|
||
|
||
# Afficher des pages avec Django
|
||
|
||
----
|
||
|
||
## Routage d'URLs
|
||
|
||
Tous les serveurs d'application web ont besoin de savoir comment afficher des pages à des URLs distinctes.
|
||
|
||
Par exemple, si vous demandez au serveur à l'adresse `https://mon.adresse.com` l'URL dont le nom est `https://mon.adresse.com/resource`, le serveur doit pouvoir définir ce qu'il va faire de la ressource dont le chemin est `/resource`. (Et en général, il doit vous renvoyer un contenu avec le code de statut HTTP 404 s'il ne le peut pas)
|
||
|
||
Pour ce faire, la majorité des systèmes de serveurs web mettent en place un système de routage d'URLs où le développeur configure quelles URLs seront acceptées par le serveur et ce qu'elles fournissent comme ressource.
|
||
|
||
----
|
||
|
||
### Exemple de routage
|
||
|
||
Si du côté du développeur, vous configurez votre site ainsi :
|
||
|
||
- Le développeur configure le routage d'URL pour accepter l'URL `/about`;
|
||
- Le développeur indique que l'URL `/about` pointera vers une fonction qui renvoie le contenu à afficher au navigateur;
|
||
|
||
Ce qui se produira lorsqu'une requête HTTP sera envoyée par votre navigateur web vers votre serveur web sera le suivant :
|
||
|
||
- Vous demandez une ressource via votre navigateur, `/about`
|
||
- Le serveur vérifie dans ses configurations d'URL si l'URL demandée correspond à une route configurée
|
||
- Si **oui**, la fonction associée à l'URL est exécutée et une réponse peut être renvoyée au navigateur
|
||
- Si **non**, le serveur renverra si possible un contenu de page avec un code HTTP 404 (ressource non trouvée)
|
||
|
||
----
|
||
|
||
## Exemple de routage d'URL dans un projet
|
||
|
||
Lorsque nous avons un nouveau projet Django dans lequel travailler, nous pouvons déclarer des URLs et rédiger du code afin que lesdites URLs nous affichent un document (HTML ou non).
|
||
|
||
La méthode imposée par le framework consiste à définir une variable possédant un nom spécifique, dans un module de votre projet qui par défaut est `urls.py` :
|
||
|
||
- La variable qui recense les URLs principales de votre projet est nommée `urlpatterns`, et est une liste de valeurs configurées via des appels d'une fonction `path`;
|
||
- Le nom du module contenant les URLs principales est configurable via la variable `settings.ROOT_URLCONF`{.python}.
|
||
|
||
----
|
||
|
||
L'exemple de code suivant est un exemple général de routes principales qu'il est possible de configurer dans Django.
|
||
|
||
```python {.numberLines}
|
||
from django.urls import path, include
|
||
|
||
urlpatterns = [
|
||
# Les URLs de l'application `application` seront accessibles dans l'URL appli/
|
||
path("appli/", include("application.urls")),
|
||
# L'URL par défaut du site reçoit un nom user-friendly (voir Cool URLs)
|
||
path("", view_function, name="<url-friendly-name>"),
|
||
# Une URL peut indiquer des parties dynamiques acceptées par le routage
|
||
path("url/<int:dynamique>", view_dynamic, name="<url-friendly-name-2>"), # URL dynamique
|
||
]
|
||
```
|
||
|
||
- [Documentation officielle](https://docs.djangoproject.com/en/dev/ref/urls/#path) de la fonction `django.urls.path`
|
||
- [Types d'emplacements dynamiques](https://docs.djangoproject.com/en/5.0/topics/http/urls/#path-converters)
|
||
|
||
----
|
||
|
||
### La fonction `django.urls.path`
|
||
|
||
Lorsque vous souhaitez définir des routes dans votre projet (ou votre application Django), vous ajoutez des résultats d'appels de la fonction `path` comme éléments de la liste contenue dans la variable `urlpatterns`.
|
||
|
||
La fonction `path` possède la signature suivante :
|
||
|
||
- `def path(route: str, view_function: Callable, kwargs: dict, name: str)`{.python}
|
||
- `route` : URL à configurer. Ne contient pas le `/` de début;
|
||
- `view_function` : référence de fonction à associer à l'URL lorsqu'on y accède;
|
||
- `name` : donner un nom à l'URL pour la référencer même si l'URL change de forme.
|
||
|
||
----
|
||
|
||
### Écrire une fonction de vue
|
||
|
||
Les fonctions de vue que vous associez à vos routes sont de simples fonctions, qui sont toujours appelées par le système de routage de Django de la même manière :
|
||
|
||
```python {.numberLines}
|
||
from django.http import HttpResponse, HttpRequest
|
||
|
||
def view_function(request: HttpRequest) -> HttpResponse:
|
||
return HttpResponse("Page content")
|
||
```
|
||
|
||
La fonction **doit** au moins posséder un premier argument positionnel nommé `request`, qui contiendra les données de requête HTTP, et retourner un objet de la classe `HttpResponse`, qui contiendra les informations de réponse HTTP (en-têtes, etc.).
|
||
|
||
----
|
||
|
||
### Décrire une simple URL statique
|
||
|
||
Pour définir une URL simple à laquelle on renvoie un contenu (page HTML ou autre document), il nous faut 2 choses, à savoir ajouter une route, et ajouter la fonction à associer à cette route :
|
||
|
||
```python {.numberLines}
|
||
from django.urls import path
|
||
|
||
urlpatterns = [
|
||
path("chemin", reference_fonction, name="nom-de-reference")
|
||
]
|
||
```
|
||
|
||
L'argument `name` de la fonction `path` permet de référencer l'URL a posteriori non pas par son chemin absolu, mais par un nom. Cet argument est recommandé, car coder en dur des URLs partout dans notre code va causer des soucis de maintenabilité dès que vous souhaiterez modifier l'URL.
|
||
|
||
```{.python}
|
||
from django.http import HttpResponse
|
||
|
||
def reference_fonction(request):
|
||
return HttpResponse("Document content")
|
||
```
|
||
|
||
----
|
||
|
||
### Inclure les URLs fournies par une application
|
||
|
||
Django propose des outils de routage avancés, et parmi ces outils, la réutilisation d'URLs définies dans une application Django.
|
||
|
||
Supposons qu'une application Django propose son propre fichier `urls.py`
|
||
avec ses propres routes. Ces routes peuvent être intégrées à votre projet en les ajoutant comme sous-URLs d'une route définie dans votre projet.
|
||
|
||
Si l'application se dédie à la gestion d'utilisateurs et définit trois sous-routes aux URLs :
|
||
|
||
- `view/<int:idx>`
|
||
- `edit/<uuid:uuid>`
|
||
- `report/<int:idx>`
|
||
|
||
Vous pouvez les intégrer à une URL de votre projet, ex. `users/`, et y accéder via les URLs suivantes :
|
||
|
||
- `users/view/<int:idx>`
|
||
- `users/edit/<uuid:uuid>`
|
||
- `users/report/<int:idx>`
|
||
|
||
----
|
||
|
||
Pour définir ce type d'URL, il vous faut :
|
||
|
||
- Une application Django (à ajouter à `settings.INSTALLED_APPS`)
|
||
- Un module `urls` dans l'application avec une configuration d'URL
|
||
- Puis, dans le module `urls` de votre projet :
|
||
|
||
```python {.numberLines}
|
||
from django.urls import path, include
|
||
|
||
urlpatterns = [
|
||
path("application/", include("application.urls", namespace="nom"))
|
||
]
|
||
```
|
||
|
||
[Documentation officielle de la fonction `include`](https://docs.djangoproject.com/en/4.1/ref/urls/#include)
|
||
|
||
----
|
||
|
||
### Espace de nom d'inclusion d'URLs
|
||
|
||
Lorsque vous utilisez la fonction `include`, vous pouvez donner un nom de "groupe" commun aux URLs incluses.
|
||
Pour cela, vous devez passer un argument `namespace` qui contiendra le nom de groupe des URLs. Vous devrez utiliser ce nom de groupe lorsque vous souhaiterez référencer ces URLs par la suite.
|
||
|
||
**Note** : Lorsque vous précisez un `namespace` dans la fonction `include`, Django refusera votre définition, à moins que vous précisiez quel est le nom de l'application incluse. La façon la plus simple de faire est d'ajouter, dans le fichier `urls.py` de votre application, une variable nommée `app_name` contenant le nom de l'application.
|
||
|
||
---
|
||
|
||
### Espace de noms d'URLs
|
||
|
||
Exemple de code pour les espaces de noms :
|
||
|
||
```python {.numberLines}
|
||
from django.urls import path, include
|
||
urlpatterns = [
|
||
path("dossier/", include("application.urls", namespace="application"))
|
||
]
|
||
```
|
||
|
||
```python {.numberLines}
|
||
# Module `application.urls`
|
||
app_name = "application" # À définir pour l'espace de noms
|
||
urlpatterns = ["…"]
|
||
```
|
||
|
||
[Documentation de include](https://docs.djangoproject.com/fr/3.2/ref/urls/#include)
|
||
|
||
----
|
||
|
||
### Éléments dynamiques d'une URL
|
||
|
||
On peut, et il vaut mieux, pouvoir définir des URLs avec des portions dynamiques, ex. `users/view/<identifiant>`.
|
||
Pour faire cela, la fonction `path` nous offre une méthode simple et efficace pour définir lesdits emplacements;
|
||
il suffit de marquer la portion dynamique entre chevrons et suivre le format suivant :
|
||
|
||
```python {.numberLines}
|
||
from django.urls import path
|
||
from application.views import view_reference
|
||
|
||
urlpatterns = [
|
||
path("view/<type:nom>/", view_reference, name="view-name")
|
||
]
|
||
```
|
||
|
||
----
|
||
|
||
Dans l'exemple précédent, la mention `type` doit être remplacée par l'un des types reconnus par le moteur de routage de Django ([Formats reconnus pour les parties dynamiques d'URL](https://docs.djangoproject.com/fr/3.2/topics/http/urls/#path-converters))
|
||
|
||
- `str` : toute chaîne de caractères non vide, sans le slash
|
||
- `int` : toute chaîne représentant un entier positif
|
||
- `slug` : uniquement des lettres latines non accentuées, chiffres, `-`, `_` et aucun espace
|
||
- `uuid` : nombre sur 128 bits représenté en hexadécimal, groupé par 8-4-4-4-12 chiffres séparés par un tiret.
|
||
- `path` : toute chaîne de caractères non vide, slash inclus
|
||
|
||
----
|
||
|
||
#### Fonction de vue et éléments dynamiques
|
||
|
||
La fonction de vue ciblée par une définition d'URL contenant une ou plusieurs portions dynamiques devra accepter un argument portant le nom défini dans la définition d'URL. Si votre définition de route est ainsi :
|
||
|
||
```python {.numberLines}
|
||
from django.urls import path
|
||
from application.views import view_reference
|
||
|
||
urlpatterns = [
|
||
path("view/<int:value>/", view_reference, name="view-name")
|
||
]
|
||
```
|
||
|
||
Alors votre définition de fonction de vue doit suivre la signature suivante :
|
||
|
||
```python {.numberLines}
|
||
# Module application.views
|
||
from django.http import HttpResponse, HttpRequest
|
||
|
||
def view_reference(request: HttpRequest, value: int = None):
|
||
"""
|
||
Fonction de vue.
|
||
|
||
L'argument `value` est converti automatiquement depuis
|
||
une chaîne (dans l'URL) vers le type à reconnaître.
|
||
"""
|
||
return HttpResponse("Texte de la page.")
|
||
```
|
||
|
||
----
|
||
|
||
## Écriture de vues
|
||
|
||
Une fois les routes définies, il faut les lier à des vues. Les vues sont de simples fonctions qui prennent au moins un argument positionnel nommé `request`. L'objet `request` contient des données relatives à la requête HTTP entrante, et la vue doit toujours renvoyer un objet de type `HttpResponse`. Il s'agit d'un contenu de réponse HTTP classique renvoyé au navigateur.
|
||
|
||
```python
|
||
def view_example(request):
|
||
return HttpResponse("Texte à renvoyer.")
|
||
```
|
||
|
||
----
|
||
|
||
Lorsqu'une vue est appelée via une URL qui accepte des portions dynamiques, la signature de la vue doit accepter des arguments du même nom que les portions dynamiques de l'URL :
|
||
|
||
```python
|
||
from django.urls import path
|
||
from somewhere import view_parametrized
|
||
|
||
urlpatterns = [
|
||
path("view/<uuid:uuid_val>/", view_parametrized, name="view-name")
|
||
]
|
||
```
|
||
|
||
```python
|
||
def view_parametrized(request, uuid_val=None):
|
||
# Récupérer l'objet possédant l'UUID ou renvoyer un
|
||
return HttpResponse("Page relative à l'UUID demandé.")
|
||
```
|
||
|
||
----
|
||
|
||
### Types de réponses disponibles
|
||
|
||
Django offre plusieurs classes de réponses pour les vues. Voici un tableau de différentes classes pour renvoyer une page 404, 403, ou une redirection avec Django :
|
||
|
||
| Type de renvoi | Description |
|
||
|-------------------------|---------------------------------------|
|
||
| `HttpResponse` | Contenu basique renvoyé au navigateur |
|
||
| `HttpResponseNotFound` | Page 404 |
|
||
| `HttpResponseForbidden` | Page 403 |
|
||
| `HttpResponseRedirect` | Redirection vers une autre URL |
|
||
|
||
Il existe toutefois de meilleurs outils pour générer des pages 404, 403 et redirections.
|
||
|
||
----
|
||
|
||
### Renvoyer des redirections
|
||
|
||
Django offre une fonction de raccourci pour renvoyer des redirections.
|
||
|
||
```python {.numberLines}
|
||
from django.shortcuts import redirect
|
||
|
||
def view_example(request):
|
||
"""Redirection vers une autre vue."""
|
||
return redirect("url-name", permanent=True)
|
||
```
|
||
|
||
La fonction `redirect`{.py} prend en argument le nom de la route vers laquelle rediriger, et accepte facultativement un argument `permanent` qui indique si la redirection est permanente ou non.
|
||
|
||
----
|
||
|
||
### HttpResponse, c'est bien mais léger
|
||
|
||
Devoir renvoyer manuellement une instance de `HttpResponse` dans chaque vue peut sembler fastidieux, notamment si l'on souhaite générer des pages complexes et interactives. Naturellement, Django propose des fonctions utilitaires pour renvoyer des contenus qui ne sont pas directement présents dans du code Python, mais dans des fichiers séparés (on parle de [templates]{.naming}).
|
||
|
||
Pas de panique, il existe des façons de renvoyer du contenu dans les vues sans créer d'objet `HttpResponse` de cette façon. On peut par exemple renvoyer le contenu d'un fichier de _template_ via des fonctions simples. (voir le chapitre sur les gabarits)
|
||
|
||
----
|
||
|
||
## Vues génériques basées sur les classes
|
||
|
||
Django 1.3 a introduit un système de vues qui sont basées sur un système de classes.
|
||
L'objectif était de rendre élégante l'écriture de vues en n'écrivant que des classes où il suffirait de préciser quelques attributs,
|
||
et ainsi créer facilement des pages intelligentes.
|
||
|
||
Dans la pratique, ça n'est pas un si beau gain de temps que prévu :
|
||
|
||
- Une vue de type fonction est souvent simple à comprendre, et s'écrit simplement.
|
||
- Il existe de nombreuses classes à connaître pour écrire des vues diverses.
|
||
- Ces classes-là possèdent également des méthodes qu'il faut connaître pour aller plus loin.
|
||
- La documentation sur le sujet est dense mais incomplète (notamment sur le système complexe de mixins)
|
||
|
||
----
|
||
|
||
### Utilité des vues basées sur les classes
|
||
|
||
Même si le système est trop complexe pour démarrer (il faut se documenter tout le temps), certaines classes de vues
|
||
sont utiles car assez concises :
|
||
|
||
- `TemplateView` : permet de rendre rapidement un template (configurable)
|
||
- `ListView` : permet d'afficher une liste d'objets
|
||
- `DetailView` : permet d'afficher la page de détail d'un objet
|
||
|
||
----
|
||
|
||
### Utiliser une classe de vue
|
||
|
||
Si l'on définit une classe de vue pour afficher le contenu d'un template :
|
||
|
||
```python
|
||
from django.views.generic import TemplateView
|
||
|
||
class MyView(TemplateView):
|
||
template_name = "nom du template"
|
||
```
|
||
|
||
```python
|
||
from django.urls import path
|
||
urlpatterns = [
|
||
path("view/", MyView.as_view(), name="view-name")
|
||
]
|
||
```
|
||
|
||
----
|
||
|
||
### Pages spéciales : 404
|
||
|
||
Imaginez que vous avez défini une URL dynamique pour afficher une page produit. L'URL existe sous la forme `view/<uuid:reference>`. Supposons qu'un visiteur arrive à une URL correspondant au format défini, mais que vous ne trouvez dans votre base de données aucun produit correspondant à la référence passée dans l'URL.
|
||
|
||
Vous souhaiterez renvoyer une page 404 classique sur votre site web. Pour ne pas vous embêter, Django propose un mécanisme simple pour rendre automatiquement une page 404 (personnalisable); il suffit de lever manuellement une exception de type `Http404`.
|
||
|
||
```python
|
||
from django.http import Http404
|
||
def my_view(request, user_id):
|
||
user = find_user(user_id)
|
||
if user is None:
|
||
raise Http404()
|
||
```
|
||
|
||
----
|
||
|
||
## Le Concept de Middleware dans Django
|
||
|
||
Un [middleware]{.naming} dans Django est une couche d'[intergiciel]{.naming} qui permet d'intercepter et de traiter les requêtes et réponses HTTP. Il s'agit d'une série de composants qui s'exécutent pendant le traitement des requêtes, offrant un moyen de modifier l'entrée ou la sortie globale de l'application.
|
||
|
||
----
|
||
|
||
### Qu'est-ce qu'un Middleware ?
|
||
|
||
Un middleware est une classe qui définit des méthodes pour intervenir à différentes étapes du cycle de traitement des requêtes et des réponses. Les méthodes les plus couramment utilisées sont :
|
||
|
||
| Méthode | Description |
|
||
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------|
|
||
| `__init__(self, get_response)` | Initialisation du middleware. |
|
||
| `__call__(self, request)` | Traitement de la requête avant qu'elle n'atteigne la vue, et de la réponse avant qu'elle ne soit renvoyée au client. |
|
||
|
||
----
|
||
|
||
### Comment Fonctionne le Middleware ?
|
||
|
||
Lorsqu'une requête est reçue, Django la passe à travers chaque middleware dans l'ordre défini dans le paramètre `MIDDLEWARE` de votre fichier `settings.py`. Chaque middleware peut :
|
||
|
||
- Modifier la requête avant qu'elle n'atteigne la vue.
|
||
- Modifier la réponse avant qu'elle ne soit renvoyée au client.
|
||
- Gérer les exceptions.
|
||
- Traiter les réponses de templates.
|
||
|
||
----
|
||
|
||
### Exemple de Middleware Intégré
|
||
|
||
Django fournit plusieurs middlewares intégrés, tels que :
|
||
|
||
|
||
| Middleware | Description |
|
||
|------------------------------|------------------------------------------------------------------------------------------|
|
||
| `AuthenticationMiddleware` | Gère l'authentification des utilisateurs (ajoute un attribut `user` à la requête, etc.). |
|
||
| `SessionMiddleware` | Gère les sessions côté serveur. |
|
||
| `CommonMiddleware` | Ajoute des améliorations utiles, comme la gestion des en-têtes HTTP. |
|
||
|
||
----
|
||
|
||
### Créer un Middleware Personnalisé
|
||
|
||
Voici comment, par exemple, créer un middleware personnalisé qui enregistre le temps pris par une vue pour s'exécuter.
|
||
|
||
```python {.numberLines}
|
||
# myapp/middleware.py
|
||
|
||
import time
|
||
|
||
class TimingMiddleware:
|
||
def __init__(self, get_response):
|
||
self.get_response = get_response
|
||
# Initialisation du middleware
|
||
|
||
def __call__(self, request):
|
||
# Code exécuté pour chaque requête avant la vue
|
||
start_time = time.time()
|
||
|
||
response = self.get_response(request)
|
||
|
||
# Code exécuté pour chaque réponse après la vue
|
||
duration = time.time() - start_time
|
||
print(f"La vue a pris {duration:.2f} secondes.")
|
||
|
||
return response
|
||
```
|
||
|
||
----
|
||
|
||
### Enregistrer le Middleware
|
||
|
||
Pour que Django utilise votre middleware, vous devez l'ajouter à la liste `MIDDLEWARE` dans `settings.py`.
|
||
|
||
```python {.numberLines}
|
||
# settings.py
|
||
MIDDLEWARE = [
|
||
# ... autres middlewares ...
|
||
'myapp.middleware.TimingMiddleware',
|
||
]
|
||
```
|
||
|
||
----
|
||
|
||
### Explication du Fonctionnement
|
||
|
||
|
||
| Méthode | Description |
|
||
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
|
||
| `__init__(self, get_response)` | Django passe la fonction `get_response` au middleware. Cette fonction est appelée pour obtenir la réponse de la vue ou du middleware suivant. |
|
||
| `__call__(self, request)` | Cette méthode est appelée pour chaque requête. Vous pouvez y ajouter du code qui s'exécute avant et après l'appel de `get_response(request)`. |
|
||
|
||
----
|
||
|
||
### Middleware avec Méthodes Additionnelles
|
||
|
||
Vous pouvez également implémenter des méthodes spécifiques pour intervenir à différentes étapes spécifiques.
|
||
|
||
```python {.numberLines}
|
||
class MyCustomMiddleware:
|
||
def __init__(self, get_response):
|
||
self.get_response = get_response
|
||
|
||
def process_view(self, request, view_func, view_args, view_kwargs):
|
||
# Code exécuté juste avant l'appel de la vue
|
||
pass
|
||
|
||
def process_exception(self, request, exception):
|
||
# Code exécuté si une exception est levée
|
||
pass
|
||
|
||
def process_template_response(self, request, response):
|
||
# Code exécuté si la réponse est un TemplateResponse
|
||
return response
|
||
```
|
||
|
||
----
|
||
|
||
### Cycle de Traitement des Requêtes
|
||
|
||
1. **Requête entrante**: Le middleware peut modifier ou rejeter la requête.
|
||
2. **Processus de la vue**: La requête est traitée par la vue.
|
||
3. **Réponse sortante**: Le middleware peut modifier la réponse avant qu'elle ne soit renvoyée.
|
||
4. **Réponse au client**: La réponse finale est envoyée au client.
|
||
|
||
----
|
||
|
||
### Cas d'Utilisation Courants
|
||
|
||
- **Authentification et Autorisation**: Contrôle d'accès aux vues.
|
||
- **Journalisation**: Enregistrement des requêtes et réponses pour le débogage.
|
||
- **Gestion des Exceptions**: Capture et traitement des erreurs.
|
||
- **Compression**: Compression des réponses pour réduire la taille des données transférées.
|
||
|
||
----
|
||
|
||
### Exemples Pratiques
|
||
|
||
Middleware pour Bloquer des IP
|
||
|
||
```python {.numberLines}
|
||
# myapp/middleware.py
|
||
|
||
class BlockIPMiddleware:
|
||
BLOCKED_IPS = ['192.168.1.1']
|
||
|
||
def __init__(self, get_response):
|
||
self.get_response = get_response
|
||
|
||
def __call__(self, request):
|
||
ip = request.META.get('REMOTE_ADDR')
|
||
if ip in self.BLOCKED_IPS:
|
||
return HttpResponseForbidden("Votre IP a été bloquée.")
|
||
response = self.get_response(request)
|
||
return response
|
||
```
|
||
|
||
----
|
||
|
||
Middleware pour Ajouter des En-têtes HTTP
|
||
|
||
```python {.numberLines}
|
||
# myapp/middleware.py
|
||
|
||
class CustomHeaderMiddleware:
|
||
def __init__(self, get_response):
|
||
self.get_response = get_response
|
||
|
||
def __call__(self, request):
|
||
response = self.get_response(request)
|
||
response['X-Custom-Header'] = 'MaValeurPersonnalisee'
|
||
return response
|
||
```
|
||
|
||
----
|
||
|
||

|
||
|
||
----
|
||
|
||
## Divers : Débogage et accès
|
||
|
||
Lorsque dans vos paramètres, `settings.DEBUG = False` (ce qui est la seule valeur acceptable en production) Django n'autorise plus l'accès à vos vues par défaut.
|
||
|
||
Pour accéder à vos vues, vous devez définir explicitement une liste d'adresses IP qui ont accès à votre site dans `settings.ALLOWED_HOSTS`. Le paramètre accepte des adresses IPv4, IPv6 et noms d'hôte. La valeur `"*"` signifie "toutes adresses".
|
||
|
||
```python {.numberLines}
|
||
# settings.py
|
||
ALLOWED_HOSTS = ("127.0.0.1", "machinea", "192.168.1.15")
|
||
```
|