Evgenii Legotckoi
Evgenii Legotckoi2 сентября 2019 г. 7:31

Django - Урок 048. Как добавить статус онлайн на сайте

Содержание

Я долго не добавлял такой функционал на сайт по той простой причине, что не знал, с какой стороны к этому подойти, ведь хотелось бы обрабатывать эту информацию в одном-единственном месте, а не в каждом View.

Со временем я начал модифицировать Backend классы для сайта и решение пришло само собой. Необходимо было только изменить каждый сервер аутентификации, который используется на сайте. И переписать метод get_user, который будет хранить информацию о последнем обращении пользователя к сайту. И статус онлайн можно сохранить за последние 15 минут, тогда статус будет офлайн.

А дату последнего запроса можно сохранить либо в профиле пользователя, который будет моделью OneToOne для пользователя, либо переопределить модель пользователя. Я выбрал вариант переопределения пользовательской модели.


my_auth

Давайте создадим собственный модуль аутентификации my_auth, если вы его еще не создали

python manage.py startapp my_auth

models.py

Затем переопределите пользовательскую модель

# -*- coding: utf-8 -*-

from django.contrib.auth.models import AbstractUser
from django.contrib.humanize.templatetags.humanize import naturaltime
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _


class User(AbstractUser):

    last_online = models.DateTimeField(blank=True, null=True)

    # In this method, check that the date of the last visit is not older than 15 minutes
    def is_online(self):
        if self.last_online:
            return (timezone.now() - self.last_online) < timezone.timedelta(minutes=15)
        return False

    # If the user visited the site no more than 15 minutes ago,
    def get_online_info(self):
        if self.is_online():
            # then we return information that he is online
            return _('Online')
        if self.last_online:
            # otherwise we write a message about the last visit
            return _('Last visit {}').format(naturaltime(self.last_online))
            # If you have only recently added information about a user visiting the site
            # then for some users there may not be any information about the visit, we will return information that the last visit is unknown
        return _('Unknown')

backends.py

Далее мы пишем собственный бэкенд аутентификации, который заменит бэкенд Django.

# -*- coding: utf-8 -*-

from django.contrib.auth import get_user_model
from django.utils import timezone


class MyBackend:

    def get_user(self, user_id):
        try:
            user = get_user_model().objects.get(pk=user_id)
            user.last_online = timezone.now()  # At the request of the user, we will update the date and time of the last visit
            user.save(update_fields=['last_online'])
            return user
        except get_user_model().DoesNotExist:
            return None

settings.py

Не забудьте зарегистрировать наше приложение...

INSTALLED_APPS = [
    'my_auth.apps.MyAuthConfig',
    ...
]

... и добавить бэкенд аутентификации

AUTHENTICATION_BACKENDS = (
    'my_auth.backends.MyBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Вывод

Теперь при каждом обращении пользователя на сайт вашему пользователю будет обновляться информация о его последнем посещении.

И вы можете сделать в шаблоне с пользователями контент, независимо от того, онлайн он или нет. Например, чтобы добавить значок «В сети» на аватар

{% if user.is_online %}
    <div class="online"></div>
{% endif %}

или так отображать информацию о его онлайн-статусе.

<span class="text-muted">{{ user_profile.get_online_info }}</span>

Возможный минус этого способа в том, что пользователь может открыть страницу и целый час ничего на ней не делать.
Но в моем случае это не проблема, потому что я каждую минуту вызываю информацию о статусе аутентифицированного пользователя, чтобы пока страница пользователя оставалась открытой, его онлайн-статус обновлялся каждую минуту.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

Владислав Меленчук
  • 3 июня 2020 г. 5:43

Доброго дня. А можно реализовать с помощью этой фичи вывод блок "Пользователи онлайн" и окрашивать взависимости от группы юзера? Как в скрине ниже.
Screenshot_36.png Screenshot_36.png

Добрый день.
Конечно, нужно будет только шаблонный тег написать, который будет забирать всех пользователей онлайн, проверяя группу текущего пользователя.
У меня пользователи онлайн на отдельной странице в разделе пользователей.

Anton
  • 21 июля 2020 г. 7:47
  • (ред.)


Здравствуйте. как внедрить эту систему если у меня уже есть авторизация и всё с ней связанное? что бы это не перекрывало весь мой код?

Evgenii Legotckoi
  • 21 июля 2020 г. 15:49

Добрый день. Вам нужно скопировать в класс AdvUser содержимое класса User из статьи. Полностью весь класс копировать не требуется.
Полагаю, что в файле settings.py у вас уже переопределён класс пользователя на ваш в переменной AUTH_USER_MODEL

Остальной код написан относительно универсально, достаточно лишь добавить файлы с содержимым как в статье в ваше существующее app аутентификации.

Также не забудьте создать миграцию и применить её, чтобы добавилось новое поле в таблице пользователя.

Anton
  • 22 июля 2020 г. 1:21

Большое спасибо!

Anton
  • 22 июля 2020 г. 3:50

И так , не все получилось. Сделал как вы говорили. И у меня как и раньше перебивает мою авторизацию. При входе в admin Вот эта ошибка

после чего я удалил из settings поле 'manager_school.backends.MyBackend'. Меня пустило. Но дело в том что(понятно что оно без этой строчки работать не будет) если я дату указываю в поле админки то мне выдаёт что человек онлайн.И даже если я выйду он всё-равно online. без этой строчки не отдаботает

И я понимаю что дело в 'manager_school.backends.MyBackend' этой строчке . но Как же мне сделать что бы он не заменял собой все настройки авторизации...?

Evgenii Legotckoi
  • 22 июля 2020 г. 4:01

Длительность сохранения статуса онлайн от последнего запроса страницы составляет 15 минут.

def is_online(self):
    if self.last_online:
        return (timezone.now() - self.last_online) < timezone.timedelta(minutes=15) # здесь выполняется эта проверка на 15 минутный интервал
    return False

Можете уменьшить на одну минуту и посмотреть результат. Вполне возможно, что у вас всё работает.

Данная система статуса онлайн не совершенна, поскольку требует периодического обращения к серверу. Чтобы обновлять время последнего статуса онлайн. У меня эта проблема решается за счёт обращения к серверу раз в одну минуту для проверки уведомлений через JavaScript. Остальные разработчики решают эту часть своими способоами, как у них это выходит.

Evgenii Legotckoi
  • 22 июля 2020 г. 4:15

Да ещё.

Покажите код ваших бэкендов аутентификации, а также как скопировали код класса MyBackend

Помимо прочего, какую версию Джанго используете?

P/S/ Используйте диалог вставки программного кода, чтобы был код с разметкой. Не надо вставлять изображения кода, на любьом форуме это считается плохим тоном.

P/P/S/ И я просил на форуме задать вопрос, а не в комментариях к статье ))

Anton
  • 22 июля 2020 г. 4:18

Спасибо за ответ. уменьшил время до 14 минут и до 10 минут , ошибка осталась та же 'MyBackend' object has no attribute 'authenticate'

Anton
  • 22 июля 2020 г. 4:26
  • (ред.)

MyBackend

from django.contrib.auth import get_user_model
from django.utils import timezone


class MyBackend:
    def get_user(self, user_id):
        try:
            user = get_user_model().objects.get(pk=user_id)
            user.last_online = timezone.now()  # При запросе пользователя выполним обновлении даты и времени последнего посещения
            user.save(update_fields=['last_online'])
            return user
        except get_user_model().DoesNotExist:
            return None

Версия Django 3.0.8
бэк аутентификации

AUTHENTICATION_BACKENDS = (
    'manager_school.backends.MyBackend',
    'django.contrib.auth.backends.ModelBackend',
)
Evgenii Legotckoi
  • 22 июля 2020 г. 4:28
  • (ред.)

Извиняюсь. Время здесь влияние не оказывает, это я ответил по поводу сохранения статуса онлайн.

Evgenii Legotckoi
  • 22 июля 2020 г. 4:29

Надо подумать. Я писал этот статус онлайн для Django 2. Вполне возможно, что для третьей версии там используется несколько иной механизм бэкендов.
Смогу посмотреть это только после работы уже.

Anton
  • 22 июля 2020 г. 7:11

Я нашел ответ на ошибку

from django.contrib.auth.backends import BaseBackend

class MyBackend(BaseBackend):
    ....
Evgenii Legotckoi
  • 22 июля 2020 г. 7:18

Ясно, значит для Django 3 обязательно наследование от BaseBackend при создание бэкенда аутентификации.
Скорее всего отсутствовал метод authenticate, который присутсвует при наследовании от BaseBackend

NSProject
  • 18 февраля 2022 г. 11:33
  • (ред.)

Хорошая статья для создания собственной батарейки для Django. Правда под каждую версию фреймворка приходится допиливать код бэкенда. Так как для версии Django 4 если наследовать бэкенд от BaseBackend то обновление статуса не происходит. Он просто проходит мимо метода get_user. По этому наследование лучше делать от ModelBackend и всё начинает работать.
Остальной весь код рабочий! Проверено на Django 4.

V
  • 2 апреля 2022 г. 13:09

Сделал всё как описано но при создании миграций возникает ошибка:
SystemCheckError: System check identified some issues:

ERRORS:
auth.User.groups: (fields.E304) Reverse accessor for 'auth.User.groups' clashes with reverse accessor for 'users.User.groups'.
HINT: Add or change a related_name argument to the definition for 'auth.User.groups' or 'users.User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'auth.User.user_permissions' clashes with reverse accessor for 'users.User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'auth.User.user_permissions' or 'users.User.user_permissions'.
users.User.groups: (fields.E304) Reverse accessor for 'users.User.groups' clashes with reverse accessor for 'auth.User.groups'.
HINT: Add or change a related_name argument to the definition for 'users.User.groups' or 'auth.User.groups'.
users.User.user_permissions: (fields.E304) Reverse accessor for 'users.User.user_permissions' clashes with reverse accessor for 'auth.User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'users.User.user_permissions' or 'auth.User.user_permissions'.

NSProject
  • 2 апреля 2022 г. 14:03
  • (ред.)

А вы создали в settings.py?

AUTH_USER_MODEL = 'you_app.User'

А так же во всех моделях где есть внешний ключ на юзера нужно ставить

settings.AUTH_USER_MODEL
NSProject
  • 26 августа 2022 г. 10:40

Евгений у меня вопрос. В общем и целом оно всё работает. Но есть маленький затык. Это так сказать дело в том что при переключении языка "Last visit" переводится а вот то что отдаёт функция "naturaltime" нет. Есть какая то возможность это исправить? Или нужно переписать код этой самой функции?

Evgenii Legotckoi
  • 2 сентября 2022 г. 5:12

Я обычно использую localtime и всё работает.

{% load tz %}

{% localtime on %}
    {{ value }}
{% endlocaltime %}

{% localtime off %}
    {{ value }}
{% endlocaltime %}

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
Дмитрий

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:60баллов,
  • Очки рейтинга-1
Дмитрий

C++ - Тест 003. Условия и циклы

  • Результат:92баллов,
  • Очки рейтинга8
d
  • dsfs
  • 26 апреля 2024 г. 14:56

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
Последние комментарии
k
kmssr9 февраля 2024 г. 5:43
Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко5 февраля 2024 г. 12:50
Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 декабря 2023 г. 21:30
Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 декабря 2023 г. 19:38
Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 декабря 2023 г. 8:01
Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Сейчас обсуждают на форуме
G
George137 мая 2024 г. 10:27
добавить qlineseries в функции в функции: "GPlotter::addSeries(QString title, QVector &arr)" я вызываю метод setChart(...), я в конструктор передал адрес на QChartView элемент
BlinCT
BlinCT5 мая 2024 г. 15:46
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
PS
Peter Son4 мая 2024 г. 3:57
Best Indian Food Restaurant In Cincinnati OH Ready to embark on a gastronomic journey like no other? Join us at App india restaurant and discover why we're renowned as the Best Indian Food Restaurant In Cincinnati OH . Whether y…
Evgenii Legotckoi
Evgenii Legotckoi3 мая 2024 г. 0:07
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
IscanderChe
IscanderChe30 апреля 2024 г. 14:22
Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…

Следите за нами в социальных сетях