Dans mon application Django, je dois commencer à exécuter quelques tâches d'arrière-plan périodiques lorsqu'un utilisateur se connecte et cesser de les exécuter lorsqu'il se déconnecte. Je recherche donc un moyen élégant de
De mon point de vue, la solution idéale serait
Django.contrib.auth.views.login
et ... views.logout
Django.contrib.auth.models.User.is_logged_in()
, analogue à ... User.is_active()
ou ... User.is_authenticated()
Django 1.1.1 ne l’a pas et j’hésite à patcher la source et à l’ajouter (je ne sais pas comment faire cela, de toute façon).
En tant que solution temporaire, j'ai ajouté un champ booléen is_logged_in
au modèle UserProfile, qui est effacé par défaut, défini la première fois que l'utilisateur accède à la page de destination (définie par LOGIN_REDIRECT_URL = '/'
) et interrogé dans les requêtes suivantes. Je l'ai ajouté à UserProfile. Je n'ai donc pas besoin de dériver et de personnaliser le modèle utilisateur intégré uniquement à cette fin.
Je n'aime pas cette solution. Si l'utilisateur clique explicitement sur le bouton de déconnexion, je peux effacer l'indicateur, mais la plupart du temps, il suffit de laisser la page ou de fermer le navigateur. Dégager le drapeau dans ces cas ne me semble pas simple. En plus (c’est plutôt une recherche de clarté dans la clarté du modèle de données), is_logged_in
n’appartient pas à UserProfile, mais au modèle User.
Quelqu'un peut-il penser aux approches alternatives?
Vous pouvez utiliser un signal comme celui-ci (je mets le mien dans models.py)
from Django.contrib.auth.signals import user_logged_in
def do_stuff(sender, user, request, **kwargs):
whatever...
user_logged_in.connect(do_stuff)
Voir la documentation Django: https://docs.djangoproject.com/en/dev/ref/contrib/auth/#module-Django.contrib.auth.signals et ici http: //docs.djangoproject. com/fr/dev/topics/signaux/
Une option pourrait consister à envelopper les vues de connexion/déconnexion de Django avec les vôtres. Par exemple:
from Django.contrib.auth.views import login, logout
def my_login(request, *args, **kwargs):
response = login(request, *args, **kwargs)
#fire a signal, or equivalent
return response
def my_logout(request, *args, **kwargs):
#fire a signal, or equivalent
return logout(request, *args, **kwargs)
Vous utilisez ensuite ces vues dans votre code plutôt que celles de Django et le tour est joué.
En ce qui concerne l’interrogation du statut de connexion, c’est assez simple si vous avez accès à l’objet request; il suffit de vérifier l'attribut utilisateur de la requête pour savoir s'il s'agit d'un utilisateur enregistré ou anonyme et le bingo. Pour citer la documentation Django :
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
Si vous n'avez pas accès à l'objet de requête, il sera difficile de déterminer si l'utilisateur actuel est connecté.
Modifier:
Malheureusement, vous ne pourrez jamais obtenir la fonctionnalité User.is_logged_in()
- c'est une limitation du protocole HTTP. Cependant, si vous faites quelques hypothèses, vous pourrez peut-être vous rapprocher de ce que vous voulez.
Premièrement, pourquoi ne pouvez-vous pas obtenir cette fonctionnalité? Eh bien, vous ne pouvez pas faire la différence entre une personne qui ferme le navigateur ou une personne qui passe du temps sur une page avant d’en récupérer une nouvelle. Il n'y a aucun moyen de savoir via HTTP si une personne quitte réellement le site ou ferme le navigateur.
Donc, vous avez deux options qui ne sont pas parfaites:
unload
de Javascript pour intercepter un utilisateur qui quitte une page. Cependant, vous devrez écrire une logique minutieuse pour vous assurer de ne pas déconnecter un utilisateur qui navigue toujours sur le site votre _.Ces solutions sont désordonnées et pas idéales, mais ce sont les meilleures que vous puissiez faire, malheureusement.
En plus de la réponse de @PhoebeB: .__, vous pouvez également utiliser le décorateur @receiver
comme ceci:
from Django.contrib.auth.signals import user_logged_in
from Django.dispatch import receiver
@receiver(user_logged_in)
def post_login(sender, user, request, **kwargs):
...do your stuff..`
Et si vous le mettez dans signals.py
dans votre répertoire d'application, ajoutez ceci à app.py
:
def ready(self):
import app_name.signals`
Déduire la déconnexion, par opposition à les faire explicitement cliquer sur un bouton (ce que personne ne fait), signifie choisir une durée d'inactivité équivalente à "déconnectée". phpMyAdmin utilise une valeur par défaut de 15 minutes; certains sites bancaires utilisent aussi peu que 5 minutes.
Le moyen le plus simple de mettre cela en œuvre serait de changer la durée de vie des cookies. Vous pouvez le faire pour l’ensemble du site en spécifiant settings.SESSION_COOKIE_AGE
. Vous pouvez également le modifier utilisateur par utilisateur (en fonction de critères arbitraires) en utilisant HttpResponse.setcookie()
. Vous pouvez centraliser ce code en créant votre propre version de render_to_response()
et en la faisant définir la durée de vie de chaque réponse.
Le seul moyen fiable (qui détecte également lorsque l'utilisateur a fermé le navigateur) est de mettre à jour un champ last_request
chaque fois que l'utilisateur charge une page.
Vous pouvez également avoir une demande périodique AJAX qui envoie une requête ping au serveur toutes les x minutes si l'utilisateur a une page ouverte.
Ensuite, créez un travail en arrière-plan avec une liste d'utilisateurs récents, créez-leur des travaux et effacez les travaux des utilisateurs ne figurant pas dans cette liste.
Idée approximative - vous pouvez utiliser un middleware pour cela. Ce middleware peut traiter les demandes et déclencher un signal lorsqu'une URL pertinente est demandée. Il pourrait également traiter les réponses et les signaux d’incendie lorsqu’une action est effectivement menée à bien.
une solution rapide pour cela serait, dans le _ _ init _ _.py de votre application, placez le code suivant:
from Django.contrib.auth.signals import user_logged_in
from Django.dispatch import receiver
@receiver(user_logged_in)
def on_login(sender, user, request, **kwargs):
print('User just logged in....')