Evgenii Legotckoi
Evgenii LegotckoiSept. 2, 2019, 7:31 a.m.

Django - Tutorial 048. How to add online status to a site

For a long time I did not add such functionality on the site for the simple reason that I did not know which side to approach this, because I would like to process this information in one single place, and not in every View.

Over time, I began to modify Backend classes for the site and the solution came by itself. It was only necessary to modify each authentication backend that is used on the site. And rewrite the get_user method, which will store information about the user's last request to the site. And the online status can be saved for the last 15 minutes, then the status will be offline.

And the date of the last request can be stored either in the user’s profile, which will be the OneToOne model for the user, or override the user model. I chose the option of overriding the user model.


my_auth

Let's create our own authentication module my_auth, if you have not created it yet

python manage.py startapp my_auth

models.py

Then redefine the user model

# -*- 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

Next, we write our own authentication backend, which will replace the Django backend.

# -*- 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

Do not forget to register our application ...

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

... and add authentication backend

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

Conclusion

Now, at each user request to the site, your user will be updated with information about his last visit.

And you can do in the template with users in the content whether it is online or not. For example, to add an Online icon to an avatar

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

or so display information about his online status.

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

A possible disadvantage of this method is that the user can open the page and do nothing for an entire hour on it.
But in my case, this is not a problem, because I call the status information of an authenticated user every minute, so that while the user’s page remains open, his online status is updated every minute.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

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

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

Anton
  • July 21, 2020, 7:47 a.m.
  • (edited)


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

Evgenii Legotckoi
  • July 21, 2020, 3:49 p.m.

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

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

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

Anton
  • July 22, 2020, 1:21 a.m.

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

Anton
  • July 22, 2020, 3:50 a.m.

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

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

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

Evgenii Legotckoi
  • July 22, 2020, 4:01 a.m.

Длительность сохранения статуса онлайн от последнего запроса страницы составляет 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
  • July 22, 2020, 4:15 a.m.

Да ещё.

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

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

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

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

Anton
  • July 22, 2020, 4:18 a.m.

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

Anton
  • July 22, 2020, 4:26 a.m.
  • (edited)

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
  • July 22, 2020, 4:28 a.m.
  • (edited)

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

Evgenii Legotckoi
  • July 22, 2020, 4:29 a.m.

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

Anton
  • July 22, 2020, 7:11 a.m.

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

from django.contrib.auth.backends import BaseBackend

class MyBackend(BaseBackend):
    ....
Evgenii Legotckoi
  • July 22, 2020, 7:18 a.m.

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

NSProject
  • Feb. 18, 2022, 11:33 a.m.
  • (edited)

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

V
  • April 2, 2022, 1:09 p.m.

Сделал всё как описано но при создании миграций возникает ошибка:
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
  • April 2, 2022, 2:03 p.m.
  • (edited)

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

AUTH_USER_MODEL = 'you_app.User'

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

settings.AUTH_USER_MODEL
NSProject
  • Aug. 26, 2022, 10:40 a.m.

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

Evgenii Legotckoi
  • Sept. 2, 2022, 5:12 a.m.

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

{% load tz %}

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

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

Comments

Only authorized users can post comments.
Please, Log in or Sign up
AD

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:50points,
  • Rating points-4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:80points,
  • Rating points4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
Last comments
Evgenii Legotckoi
Evgenii LegotckoiOct. 31, 2024, 2:37 p.m.
Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEOct. 19, 2024, 8:19 a.m.
Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовOct. 5, 2024, 7:51 a.m.
Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5July 5, 2024, 11:02 a.m.
QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrFeb. 8, 2024, 6:43 p.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Now discuss on the forum
Evgenii Legotckoi
Evgenii LegotckoiJune 24, 2024, 3:11 p.m.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Nov. 15, 2024, 6:04 a.m.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectJune 4, 2022, 3:49 a.m.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimOct. 25, 2024, 9:10 a.m.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Follow us in social networks