Django: сигнал, когда пользователь входит в систему?
В моем приложении Django мне нужно запустить несколько периодических фоновых заданий, когда пользователь входит в систему и перестает запускать их, когда пользователь выходит из системы, поэтому я ищу элегантный способ
- получить уведомление о входе/выходе пользователя
- запрашивать статус входа пользователя
С моей точки зрения, идеальным решением было бы
- сигнал, отправленный каждым
django.contrib.auth.views.login
и ... views.logout
- метод
django.contrib.auth.models.User.is_logged_in()
, аналогичный ... User.is_active()
или ... User.is_authenticated()
В Django 1.1.1 этого нет, и я не хочу исправлять исходный код и добавлять его (не знаю, как это сделать, так или иначе).
В качестве временного решения я добавил логическое поле is_logged_in
в модель UserProfile, которая по умолчанию очищается, устанавливается при первом обращении пользователя к целевой странице (определяется LOGIN_REDIRECT_URL = '/'
) и запрашивается в последующих Запросы. Я добавил его в UserProfile, поэтому мне не нужно выводить и настраивать встроенную модель пользователя только для этой цели.
Мне не нравится это решение. Если пользователь явно нажимает кнопку выхода, я могу очистить флаг, но большую часть времени пользователи просто покидают страницу или закрывают браузер; очистка флага в этих случаях не кажется мне прямой. Кроме того (что, скорее, ясность четности данных модели), is_logged_in
не принадлежит в UserProfile, а в модели User.
Может ли кто-нибудь подумать об альтернативных подходах?
Ответы
Ответ 1
Вы можете использовать такой сигнал (я поместил mine в 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)
См. django docs: https://docs.djangoproject.com/en/dev/ref/contrib/auth/#module-django.contrib.auth.signals и здесь http://docs.djangoproject.com/en/dev/topics/signals/
Ответ 2
Один из вариантов может состоять в том, чтобы объединить виды входа/выхода в Django с вашим собственным. Например:
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)
Затем вы используете эти представления в своем коде, а не в Django и voila.
Что касается запроса статуса входа в систему, это довольно просто, если у вас есть доступ к объекту запроса; просто проверьте атрибут пользователя запроса, чтобы узнать, являются ли они зарегистрированным пользователем или анонимным пользователем, а также бинго. Чтобы процитировать документацию Django:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
Если у вас нет доступа к объекту запроса, определение того, будет ли текущий пользователь зарегистрирован, будет затруднительным.
Edit:
К сожалению, вы никогда не сможете получить функциональность User.is_logged_in()
- это ограничение протокола HTTP. Однако, если вы сделаете несколько предположений, вы сможете приблизиться к тому, что хотите.
Во-первых, почему вы не можете получить эту функциональность? Ну, вы не можете сказать разницу между тем, кто закрывает браузер, или кто-то тратит время на странице, прежде чем выберет новый. Невозможно передать HTTP-сообщение, когда кто-то действительно покидает сайт или закрывает браузер.
Итак, у вас есть два варианта, которые не идеальны:
- Использовать Javascript
unload
, чтобы поймать, когда пользователь покидает страницу. Вы должны написать некоторую осторожную логику, чтобы убедиться, что вы не выходите из системы, когда пользователь все еще перемещает ваш сайт.
- Огоньте сигнал выхода, когда пользователь входит в систему, чтобы быть уверенным. Также создайте задание cron, которое выполняется довольно часто, чтобы очистить сеансы с истекшим сроком действия - при удалении истекшего сеанса убедитесь, что пользователь сеанса (если он не анонимный) не имеет более активных сеансов, и в этом случае вы запускаете сигнал выхода из системы.
Эти решения беспорядочны и не идеальны, но, к сожалению, это лучшее, что вы можете сделать.
Ответ 3
В дополнение к @PhoebeB ответ:
вы также можете использовать декоратор @receiver
следующим образом:
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..`
И если вы поместите его в signals.py
в свой каталог приложений, добавьте его в app.py
:
def ready(self):
import app_name.signals`
Ответ 4
Единственный надежный способ (который также обнаруживает, когда пользователь закрыл браузер) заключается в обновлении некоторого поля last_request
каждый раз, когда пользователь загружает страницу.
У вас также может быть периодический запрос AJAX, который связывает сервер каждые x минут, если у пользователя открыта страница.
Затем у вас есть одно фоновое задание, которое получает список последних пользователей, создает задания для них и очищает задания для пользователей, не присутствующих в этом списке.
Ответ 5
Вывод выхода из системы, в отличие от того, что они явно нажимают кнопку (что никто не делает), означает выбор количества простоя, которое приравнивается к "выходу из системы". phpMyAdmin использует по умолчанию 15 минут, некоторые банковские сайты используют всего 5 минут.
Самый простой способ реализовать это - изменить время жизни cookie. Вы можете сделать это для всего своего сайта, указав settings.SESSION_COOKIE_AGE
. В качестве альтернативы вы можете изменить его для каждого пользователя (на основе некоторого произвольного набора критериев), используя HttpResponse.setcookie()
. Вы можете централизовать этот код, создав собственную версию render_to_response()
и установив для каждого ответа время жизни.
Ответ 6
Грубая идея - для этого вы можете использовать промежуточное ПО. Это промежуточное программное обеспечение может обрабатывать запросы и сигнал пожара, когда запрашивается соответствующий URL-адрес. Он также может обрабатывать ответы и сигнал огня, когда данное действие действительно выполняется.
Ответ 7
быстрое решение для этого было бы в _ _ init _ _.py вашего приложения разместить следующий код:
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....')
Ответ 8
Вы можете использовать следующее:
from django.contrib.auth.signals import user_logged_out, user_logged_in
@login_required
def user_logout(request):
logout(request)
user_logged_out()
return redirect('post_list')