Comment utiliser les sessions
Django fournit un support complet de sessions anonymes. Le système de sessions vous permet de stocker et de retrouver les données que vous souhaitez par visiteur de votre site. Il stocke les données côté serveur et fournit une couche d'abstraction pour l'envoi et la réception des cookies. Les cookies contiennent une ID de session -- pas les données elles-mêmes.
Mise en place des sessions
Les sessions sont mises en place via un middleware.
Pour mettre en place la fonctionnalité de sessions, faites ce qui suit :
Editez la variable de réglage MIDDLEWARE_CLASSES et assurez vous qu'elle contient 'django.contrib.sessions.middleware.SessionMiddleware'. C'est déjà le cas dans le fichier settings.py créé par Django par défaut.
Ajoutez 'django.contrib.sessions' à la variable INSTALLED_APPS, et exécutez manage.py syncdb pour installer la table qui stocke les données de session dans la base de données.
Nouveau dans la version de développement : cette étape n'est pas obligatoire si vous n'utilisez pas le backend de sessions de la base de données, voir configuration du moteur de sessions.
Si vous ne souhaitez pas utiliser les sessions, vous pouvez retirer la ligne SessionMiddleware de MIDDLEWARE_CLASSES et 'django.contrib.sessions' de INSTALLED_APPS. Cela épargnera un peu de travail à votre Django.
Configuration du moteur de sessions
Nouveau dans la version de développement
Par défaut, Django stocke les données de session en base de données (en utilisant le modèle django.contrib.sessions.models.Session). Bien que cela soit pratique, il existe des cas dans lesquels il est plus rapide de stocker les données de session ailleurs, et Django peut être configuré pour utiliser le système de fichier ou le cache à cet effet.
Utiliser des sessions basées sur un fichier
Pour utiliser des sessions dont les données sont stockées dans un fichier, donnez au réglage SESSION_ENGINE la valeur django.contrib.sessions.backends.file.
Vous pouvez aussi utiliser le réglage SESSION_FILE_PATH (dont la valeur par défaut est fournie par tempfile.gettempdir(), soit probablement /tmp) pour contrôler l'endroit où Django placera les fichiers de session. Assurez-vous que votre serveur Web a les permissions nécessaires pour lire et écrire à cet emplacement.
Utiliser des sessions basées sur le cache
Pour stocker les données de session en utilisant le système de cache de Django, donnez au réglage SESSION_ENGINE la valeur django.contrib.sessions.backends.cache. Assurez-vous d'avoir configuré votre cache correctement, voyez la documentation du cache pour plus de détails.
Note
Vous ne devriez probablement utiliser des sessions basées sur le cache que si votre système de cache est memcached. La mémoire locale et les backends de cache simples ne conservent pas les données suffisamment longtemps pour être de bons choix, et il est plus rapide d'avoir directement des sessions utilisant le système de fichiers ou la base de données que d'avoir des backends de cache en base de données ou en fichier.
Utiliser les sessions dans les vues
Quand SessionMiddleware est activé, chaque objet HttpRequest -- le premier argument de toutes les fonctions vues de Django -- aura un attribut session, qui est un objet de type dictionnaire. Vous pouvez le lire et y écrire.
Il implémente les méthodes standards de dictionnaires suivantes :
__getitem__(key)
Exemple: fav_color = request.session['fav_color']
__setitem__(key, value)
Exemple: request.session['fav_color'] = 'blue'
__delitem__(key)
Exemple: del request.session['fav_color']. Lève l'exception KeyError si la clé key n'existe pas déjà dans la session.
__contains__(key)
Exemple: 'fav_color' in request.session
get(key, default=None)
Exemple: fav_color = request.session.get('fav_color', 'red')
keys()
items()
setdefault() (Nouveau dans la version de développement de Django)
Il possède aussi ces méthodes :
set_test_cookie()
Place un cookie de test pour vérifier que le navigateur de l'utilisateur accepte les cookies. Compte tenu du mode de fonctionnement des cookies, on ne peut pas le tester avant la prochaine requête de l'utilisateur. Voir Mise en place de cookies de test ci-dessous pour plus d'informations.
test_cookie_worked()
Renvoie True si le navigateur de l'utilisateur a accepté le cookie de test, False sinon. En raison du mode de fonctionnement des cookies, vous devrez appeler set_test_cookie() sur une page précédente appelée dans une autre requête. Voir Mise en place de cookies de test ci-dessous pour plus d'informations.
delete_test_cookie()
Efface le cookie de test. Utilisez cette fonction pour faire le ménage après le test.
set_expiry(value)
Nouveau dans la version de développement de Django
Positionne la date d'expiration de la session. Vous pouvez passer les valeurs de façon différente :
- Si value est un entier, la session expirera après ce nombre de secondes d'inactivité. Par exemple, appeller request.session.set_expiry(300) fera se terminer la session après 5 minutes d'inactivité.
- Si value est un objet datetime ou timedelta, la session expirera à la date et l'heure spécifiées.
- Si value est 0, la session de l'utilisateur expirera lorsque le navigateur de l'utilisateur sera fermé.
- Si value est None, la session utilisera la politique globale d'expiration des sessions.
get_expiry_age()
Nouveau dans la version de développement de Django
Renvoie le nombre de secondes avant l'expiration de cette session. Pour les sessions sans date d'expiration spécifique (ou celles qui expirent à la fermeture du navigateur), la valeur renvoyée vaudra settings.SESSION_COOKIE_AGE.
get_expiry_date()
Nouveau dans la version de développement de Django
Renvoie la date à laquelle la session expirera. Pour les sessions sans date d'expiration spécifique (ou celles qui expirent à la fermeture du navigateur), la valeur renvoyée sera à sessions.SESSION_COOKIE_AGE de l'instant présent.
get_expire_at_browser_close()
Nouveau dans la version de développement de Django
Renvoie True ou False, selon que la session de l'utilisateur devra expirer quand son navigateur est fermé, ou non.
Vous pouvez éditer request.session où vous le souhaitez dans vos vues. Vous pouvez également l'éditer à plusieurs reprises.
Comment utiliser l'objet Session
- Utilisez des chaînes Python classiques comme clés du dictionnaire request.session. Il s'agit en fait plus d'une convention que d'une règle absolue.
- Les clés du dictionnaire de session qui commencent par un tiret de soulignement (underscore) sont réservées à Django (usage interne).
- Ne surchargez pas request.session avec un nouvel objet, et ne changez pas ou n'accédez pas directement à ses attributs. Utilisez-le comme un dictionnaire Python.
Exemples
Cette vue un peu simpliste positionne la variable has_commented à True après qu'un utilisateur ait posté un commentaire. Elle empêche qu'un utilisateur poste un commentaire plus d'une fois:
def post_comment(request, new_comment):
if request.session.get('has_commented', False):
return HttpResponse("Vous avez déjà posté un commentaire.")
c = comments.Comment(comment=new_comment)
c.save()
request.session['has_commented'] = True
return HttpResponse('Merci de votre commentaire !')
Cette vue très simple authentifie un "membre" du site:
def login(request):
m = Member.objects.get(username=request.POST['username'])
if m.password == request.POST['password']:
request.session['member_id'] = m.id
return HttpResponse("Vous êtes authentifié.")
else:
return HttpResponse("Mot de passe incorrect.")
... Et celle-ci déconnecte un membre qui s'est connecté avec la vue login() ci-dessus:
def logout(request):
try:
del request.session['member_id']
except KeyError:
pass
return HttpResponse("Vous êtes déconnecté.")
Mise en place de cookies de test
Django vous permet facilement de tester si le navigateur de l'utilisateur accepte les cookies. Appelez simplement request.session.set_test_cookie() dans une vue, puis appelez request.session.test_cookie_worked() dans la vue suivante -- pas dans la même vue.
Cette séparation un peu pénible entre set_test_cookie() et test_cookie_worked est nécessaire à cause du mode de fonctionnement des cookies. Quand vous positionnez un cookie, vous ne pouvez pas savoir si le navigateur l'a accepté avant la requête suivante.
Il est recommandé d'utiliser delete_test_cookie() pour supprimer le cookie de test après l'avoir utilisé. Faites-le après avoir vérifié que ce cookie a été accepté.
Voici un exemple classique d'utilisation:
def login(request):
if request.method == 'POST':
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponse("Vous êtes connecté.")
else:
return HttpResponse("Activez le support des cookies dans votre navigateur et faites un nouvel essai .")
request.session.set_test_cookie()
return render_to_response('foo/login_form.html')
Utilisation des sessions en dehors des vues
Nouveau dans la version de développement de Django
Une API est disponible pour manipuler les données de session en dehors des vues:
>>> from django.contrib.sessions.backends.db import SessionStore >>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead') >>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10) >>> s['last_login'] datetime.datetime(2005, 8, 20, 13, 35, 0) >>> s.save()
Si vous utilisez le backend django.contrib.sessions.backends.db, chaque session est simplement un modèle Django. L'objet Session est défini dans django/contrib/sessions/models.py. Parce qu'il s'agit d'un modèle comme les autres, vous pouvez accéder aux sessions en utilisant l'API de base de données de Django habituelle:
>>> from django.contrib.sessions.models import Session >>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead') >>> s.expire_date datetime.datetime(2005, 8, 20, 13, 35, 12)
Notez que vous devrez utiliser la fonction get_decoded() pour obtenir le dictionnaire de session. C'est nécessaire parce que le dictionnaire est stocké dans un format encodé particulier:
>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}
Quand les sessions sont-elles sauvegardées ?
Par défaut, Django ne sauvegarde les données de la session que quand la session est modifiée -- c'est-à-dire si l'une des valeurs du dictionnaire est créée, modifiée ou supprimée:
# La session est modifiée.
request.session['foo'] = 'bar'
# La session est modifiée.
del request.session['foo']
# La session est modifiée.
request.session['foo'] = {}
# Attention : la session N'EST PAS modifiée, parce qu'on modifie
# request.session['foo'] et non request.session.
request.session['foo']['bar'] = 'baz'
Dans le dernier cas de l'exemple ci-dessus, on peut indiquer explicitement à l'objet session qu'il a été modifié en positionnant l'attribut modified sur celui-ci:
request.session.modified = True
Pour modifier ce comportement par défaut, positionnez la variable SESSION_SAVE_EVERY_REQUEST à True. Si c'est le cas, Django sauvegardera la session dans la base de données à chaque requête.
Notez que le cookie de session n'est envoyé que lorsque la session est créée ou modifiée. Si SESSION_SAVE_EVERY_REQUEST vaut True, le cookie de session sera envoyé à chaque requête.
De la même façon, la partie expiration (expires) d'un cookie est mise à jour à chaque fois que le cookie de session est envoyé.
Sessions temporaires ou sessions persistantes
Vous pouvez contrôler si le système de sessions utilise des sessions temporaires (qui ne durent que le temps de la navigation de l'utilisateur sur le site) ou des sessions persistantes avec la variable SESSION_EXPIRE_AT_BROWSER_CLOSE.
Par défaut, la variable SESSION_EXPIRE_AT_BROWSER_CLOSE vaut False, ce qui signifie que les cookies de sessions seront stockés par les navigateurs des utilisateurs pour une durée égale à SESSION_COOKIE_AGE. Utilisez ces réglages si vous voulez éviter à vos utilisateurs de s'authentifier à chaque fois qu'ils démarrent leur navigateur.
Si SESSION_EXPIRE_AT_BROWSER_CLOSE est positionné sur True, Django utilisera des cookies temporaires, qui expirent lorsque l'utilisateur ferme son navigateur. Utilisez ce réglage si vous voulez forcer vos utilisateurs à s'authentifier à chaque fois qu'ils ouvrent leur navigateur.
Nouveau dans la version de développement de Django
Ce règlage est une valeur par défaut globale, et peut être surchargée session par session en utilisant explicitement request.session.set_expiry() comme décrit ci-dessus dans Utiliser les sessions dans les vues.
Purger la table des sessions
Notez que les données de sessions peuvent s'accumuler dans la table django_session dans la base de données, et Django ne fournit pas de système de purge automatique. Il est donc de votre responsabilité de purger régulièrement les sessions expirées.
Pour comprendre ce problème, considérez ce qui se passe quand un utilisateur utilise une session. Quand il s'authentifie, Django ajoute une ligne à la table django_session dans la base de données. Django met à jour cette ligne chaque fois que les données de session changent. Si l'utilisateur se déconnecte volontairement, Django détruit la ligne. Mais si l'utilisateur ne se déconnecte pas, la ligne n'est jamais détruite.
Django fournit un exemple de script de nettoyage dans django-admin.py cleanup. Ce script détruit toutes les sessions de la table dont la date d'expiration (expire_date) est dans le passé -- mais votre application peut avoir des besoins différents.
Règlages
Quelques règlages de Django vous permettent de contrôler vos sessions :
SESSION_ENGINE
Nouveau dans la version de développement de Django
Valeur par défaut : django.contrib.sessions.backends.db
Contrôle où Django stocke les données de session. Les valeurs possibles sont :
- 'django.contrib.sessions.backends.db'
- 'django.contrib.sessions.backends.file'
- 'django.contrib.sessions.backends.cache'
Voir configuration du moteur de sessions pour plus de détails.
SESSION_FILE_PATH
Nouveau dans la version de développement de Django
Valeur par défaut : /tmp/
Si vous utilisez le stockage de données de session dans le système de fichiers, ceci indique le répertoire dans lequel Django stockera les données de session.
SESSION_COOKIE_AGE
Valeur par défaut : 1209600 (2 semaines, en secondes)
L'âge maximum du cookie de session, en secondes.
SESSION_COOKIE_DOMAIN
Valeur par défaut : None
Le nom de domaine à utiliser pour les cookies de session. Utilisez une chaîne comme ".lawrence.com" pour les cookies qui doivent couvrir plusieurs sous-domaines, ou laissez None pour les cookies de domaines standards.
SESSION_COOKIE_NAME
Valeur par défaut : 'sessionid'
Le nom du cookie à utiliser pour les sessions. Peut être ce que vous voulez.
SESSION_COOKIE_SECURE
Valeur par défaut : False
Pour déterminer s'il faut utiliser un cookie sécurisé pour la session. Si la valeur est True, le cookie sera marqué comme "sécurisé", ce qui signifie que le navigateur peut vérifier que le cookie n'est envoyé qu'au travers d'une connexion sécurisée HTTPS.
SESSION_EXPIRE_AT_BROWSER_CLOSE
Valeur par défaut : False
Pour déterminer si la session doit expirer lorsque l'utilisateur ferme son navigateur. Voir "Sessions temporaires ou sessions persistantes" ci-dessus.
SESSION_SAVE_EVERY_REQUEST
Valeur par défaut : False
Pour déterminer s'il faut sauvegarder les données de session à chaque requête. Si la valeur est False (valeur par défaut), les données de session ne seront sauvegardées que lorsqu'elles sont modifiées -- c'est-à-dire si une quelconque donnée du dictionnaire est créée, modifiée ou effacée.
Détails techniques
- Le dictionnaire de sessions devrait accepter tout objet sérialisable de Python. Voir le module pickle pour plus de détails.
- Les données de session sont stockées dans la table de la base de données appelée django_session.
- Django n'envoie un cookie que s'il en a besoin. Si vous ne créez aucune donnée de session, aucun cookie ne sera envoyé.
ID de session dans les URL
Le système de sessions de Django est entièrement et exclusivement basé sur les cookies. Il ne placera pas les ID de session dans les URL en dernier ressort, comme le fait PHP. C'est une décision intentionnelle. En effet, la technique des ID de session dans les URL n'a pas seulement pour effet de rendre celles-ci affreuses, elle rend également votre site vulnérable au vol d'ID de session via l'entête "Referer".