En mi aplicación Django, necesito comenzar a ejecutar algunos trabajos en segundo plano periódicos cuando un usuario inicia sesión y dejar de ejecutarlos cuando el usuario cierra sesión, así que estoy buscando una forma elegante de
- ser notificado de un inicio de sesión / cierre de sesión de usuario
- consultar el estado de inicio de sesión del usuario
Desde mi perspectiva, la solución ideal sería
- una señal enviada por todos
django.contrib.auth.views.login
y... views.logout
- un método
django.contrib.auth.models.User.is_logged_in()
, análogo... User.is_active()
o... User.is_authenticated()
Django 1.1.1 no tiene eso y soy reacio a parchear la fuente y agregarla (no estoy seguro de cómo hacerlo, de todos modos).
Como solución temporal, agregué un is_logged_in
campo booleano al modelo UserProfile que se borra de manera predeterminada, se establece la primera vez que el usuario ingresa a la página de destino (definida por LOGIN_REDIRECT_URL = '/'
) y se consulta en solicitudes posteriores. Lo agregué a UserProfile, por lo que no tengo que derivar y personalizar el modelo de usuario incorporado solo para ese propósito.
No me gusta esta solución. Si el usuario hace clic explícitamente en el botón de cierre de sesión, puedo borrar la marca, pero la mayoría de las veces, los usuarios simplemente abandonan la página o cierran el navegador; limpiar la bandera en estos casos no me parece sencillo. Además (aunque eso es más bien una nitidez del modelo de datos), is_logged_in
no pertenece al UserProfile, sino al modelo User.
¿Alguien puede pensar en enfoques alternativos?
Respuestas:
Puedes usar una señal como esta (puse la mía en 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)
Consulte los documentos de django: https://docs.djangoproject.com/en/dev/ref/contrib/auth/#module-django.contrib.auth.signals y aquí http://docs.djangoproject.com/en/dev/ temas / señales /
fuente
models.py
lugar, sugiero colocar el códigosignals.py
e importarlo automáticamente en el__init__.py
archivo de los módulos .Además de la respuesta de @PhoebeB: también puede usar el
@receiver
decorador como este: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..
Y si lo pones
signals.py
en el directorio de tu aplicación, agrega esto aapps.py
:class AppNameConfig(AppConfig): ... def ready(self): import app_name.signals
fuente
Una opción podría ser envolver las vistas de inicio / cierre de sesión de Django con las suyas. Por ejemplo:
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)
Luego usa estas vistas en su código en lugar de Django, y listo.
Con respecto a la consulta del estado de inicio de sesión, es bastante simple si tiene acceso al objeto de solicitud; simplemente verifique el atributo de usuario de la solicitud para ver si es un usuario registrado o el usuario anónimo, y bingo. Para citar la documentación de Django :
if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users.
Si no tiene acceso al objeto de solicitud, será difícil determinar si el usuario actual está conectado.
Editar:
Desafortunadamente, nunca podrá obtener la
User.is_logged_in()
funcionalidad; es una limitación del protocolo HTTP. Sin embargo, si hace algunas suposiciones, es posible que pueda acercarse a lo que desea.Primero, ¿por qué no puede obtener esa funcionalidad? Bueno, no se puede notar la diferencia entre alguien que cierra el navegador o alguien que pasa un tiempo en una página antes de buscar una nueva. No hay forma de saber a través de HTTP cuándo alguien abandona el sitio o cierra el navegador.
Entonces tienes dos opciones aquí que no son perfectas:
unload
evento de Javascript para detectar cuándo un usuario abandona una página. Sin embargo, tendría que escribir una lógica cuidadosa para asegurarse de no cerrar la sesión de un usuario cuando todavía está navegando por su sitio.Estas soluciones son complicadas y no son ideales, pero desafortunadamente son lo mejor que puede hacer.
fuente
is_logged_in
cosas muy bien (disculpas, supongo que no hice un gran trabajo al leer la publicación), pero actualicé la respuesta para ofrecer la ayuda que puedo en esa área. . Es un problema un poco imposible, desafortunadamente.una solución rápida para esto sería, en el _ _ init _ _.py de su aplicación coloque el siguiente código:
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....')
fuente
La única forma confiable (que también detecta cuando el usuario ha cerrado el navegador) es actualizar algún
last_request
campo cada vez que el usuario carga una página.También podría tener una solicitud AJAX periódica que haga ping al servidor cada x minutos si el usuario tiene una página abierta.
Luego, tenga un único trabajo en segundo plano que obtenga una lista de usuarios recientes, cree trabajos para ellos y borre los trabajos para los usuarios que no están presentes en esa lista.
fuente
Inferir el cierre de sesión, en lugar de hacer que hagan clic explícitamente en un botón (lo que nadie hace), significa elegir una cantidad de tiempo de inactividad que equivale a "cerrar sesión". phpMyAdmin usa un valor predeterminado de 15 minutos, algunos sitios bancarios usan tan solo 5 minutos.
La forma más sencilla de implementar esto sería cambiar la duración de la cookie. Puede hacer esto para todo su sitio especificando
settings.SESSION_COOKIE_AGE
. Alternativamente, puede cambiarlo por usuario (basado en un conjunto arbitrario de criterios) usandoHttpResponse.setcookie()
. Puede centralizar este código creando su propia versiónrender_to_response()
y estableciendo la duración de cada respuesta.fuente
Idea aproximada: podría usar middleware para esto. Este middleware podría procesar solicitudes y disparar señales cuando se solicita una URL relevante. También podría procesar respuestas y señales de disparo cuando una determinada acción realmente tuvo éxito.
fuente