- 1. my_auth
- 1. models.py
- 2. backends.py
- 3. settings.py
- 2. Висновок
Довгий час не додавав подібний функціонал на сайті з тієї простої причини, що не знав, з якого б боку до цього підійти, оскільки хотілося б обробляти цю інформацію в одному єдиному місці, а не в кожному 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) # В даному методі перевірка, що дата останнього відвідування не старше 15 хвилин def is_online(self): if self.last_online: return (timezone.now() - self.last_online) < timezone.timedelta(minutes=15) return False # Якщо користувач відвідував сайт не більше 15 хвилин назад, def get_online_info(self): if self.is_online(): # то повертаємо інформацію, що він онлайн return _('Online') if self.last_online: # інакше пишемо повідомлення про останньому відвідуванні return _('Last visit {}').format(naturaltime(self.last_online)) # Якщо ви тільки недавно додали інформацію про відвідування користувачем сайту # То для деяких користувачів інфомація про відвідування може і не бути, повернемо інформацію, що останній візит невідомо 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() # При запиті користувача виконаємо оновленні дати і часу останнього відвідування 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', )
Висновок
Тепер при кожному запиті користувача до сайту у вашого полььзователя буде оновлюватися інформація про його останньому відвідуванні.
І ви зможете в шаблоні робити у пользовтелей в контенті, чи знаходиться він онлайн чи ні. Наприклад так, щоб додати значок Online у аватарки
{% if user.is_online %} <div class="online"></div> {% endif %}
або так відображати інформацію про його онлацн статус.
<span class="text-muted">{{ user_profile.get_online_info }}</span>
Можливий недолік даного методу полягає в тому, що користувач може відкрити сторінку і нічого не робити цілу годину на ній.
Але в моєму випадку це не є проблемою, оскільки я кожну хвилину викликаю перевірку статусної інформації у аутентифицированного користувача, таким чином, поки сторінка користувача залишається відкритою, кожну хвилину оновлюється його статус онлайн.
Доброго дня. А можно реализовать с помощью этой фичи вывод блок "Пользователи онлайн" и окрашивать взависимости от группы юзера? Как в скрине ниже.
Screenshot_36.png
Добрый день.
Конечно, нужно будет только шаблонный тег написать, который будет забирать всех пользователей онлайн, проверяя группу текущего пользователя.
У меня пользователи онлайн на отдельной странице в разделе пользователей.
Здравствуйте. как внедрить эту систему если у меня уже есть авторизация и всё с ней связанное? что бы это не перекрывало весь мой код?
Добрый день. Вам нужно скопировать в класс AdvUser содержимое класса User из статьи. Полностью весь класс копировать не требуется.
Полагаю, что в файле settings.py у вас уже переопределён класс пользователя на ваш в переменной AUTH_USER_MODEL
Остальной код написан относительно универсально, достаточно лишь добавить файлы с содержимым как в статье в ваше существующее app аутентификации.
Также не забудьте создать миграцию и применить её, чтобы добавилось новое поле в таблице пользователя.
Большое спасибо!
И так , не все получилось. Сделал как вы говорили. И у меня как и раньше перебивает мою авторизацию. При входе в admin Вот эта ошибка
после чего я удалил из settings поле 'manager_school.backends.MyBackend'. Меня пустило. Но дело в том что(понятно что оно без этой строчки работать не будет) если я дату указываю в поле админки то мне выдаёт что человек онлайн.И даже если я выйду он всё-равно online. без этой строчки не отдаботает
И я понимаю что дело в 'manager_school.backends.MyBackend' этой строчке . но Как же мне сделать что бы он не заменял собой все настройки авторизации...?
Длительность сохранения статуса онлайн от последнего запроса страницы составляет 15 минут.
Можете уменьшить на одну минуту и посмотреть результат. Вполне возможно, что у вас всё работает.
Данная система статуса онлайн не совершенна, поскольку требует периодического обращения к серверу. Чтобы обновлять время последнего статуса онлайн. У меня эта проблема решается за счёт обращения к серверу раз в одну минуту для проверки уведомлений через JavaScript. Остальные разработчики решают эту часть своими способоами, как у них это выходит.
Да ещё.
Покажите код ваших бэкендов аутентификации, а также как скопировали код класса MyBackend
Помимо прочего, какую версию Джанго используете?
P/S/ Используйте диалог вставки программного кода, чтобы был код с разметкой. Не надо вставлять изображения кода, на любьом форуме это считается плохим тоном.
P/P/S/ И я просил на форуме задать вопрос, а не в комментариях к статье ))
Спасибо за ответ. уменьшил время до 14 минут и до 10 минут , ошибка осталась та же 'MyBackend' object has no attribute 'authenticate'
MyBackend
Версия Django 3.0.8
бэк аутентификации
Извиняюсь. Время здесь влияние не оказывает, это я ответил по поводу сохранения статуса онлайн.
Надо подумать. Я писал этот статус онлайн для Django 2. Вполне возможно, что для третьей версии там используется несколько иной механизм бэкендов.
Смогу посмотреть это только после работы уже.
Я нашел ответ на ошибку
Ясно, значит для Django 3 обязательно наследование от BaseBackend при создание бэкенда аутентификации.
Скорее всего отсутствовал метод authenticate, который присутсвует при наследовании от BaseBackend
Хорошая статья для создания собственной батарейки для Django. Правда под каждую версию фреймворка приходится допиливать код бэкенда. Так как для версии Django 4 если наследовать бэкенд от BaseBackend то обновление статуса не происходит. Он просто проходит мимо метода get_user. По этому наследование лучше делать от ModelBackend и всё начинает работать.
Остальной весь код рабочий! Проверено на Django 4.
Сделал всё как описано но при создании миграций возникает ошибка:
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'.
А вы создали в settings.py?
А так же во всех моделях где есть внешний ключ на юзера нужно ставить
Евгений у меня вопрос. В общем и целом оно всё работает. Но есть маленький затык. Это так сказать дело в том что при переключении языка "Last visit" переводится а вот то что отдаёт функция "naturaltime" нет. Есть какая то возможность это исправить? Или нужно переписать код этой самой функции?
Я обычно использую localtime и всё работает.