Создание сайта на Django: Урок 48, добавление статуса онлайн
avatar
7 | (offline)
❤️‍🔥Notehunter Developer
Добавлено:
Категория: Руководства «Django»
Комментариев: 0

Создание middleware для статуса онлайн

В модуле system я добавлю папку middleware с файлом __init__.py, а в ней создам файл activeuser.py

modules/system/middleware/activeuser.py

from django.contrib.auth.models import User
from django.core.cache import cache
from django.utils import timezone
from django.utils.deprecation import MiddlewareMixin


class ActiveUserMiddleware(MiddlewareMixin):

    def process_request(self, request):
        if request.session.session_key:
            cache_key = f'last-seen-{request.session.session_key}'
            last_login = cache.get(cache_key)

            if not last_login and request.user.is_authenticated:
                User.objects.filter(id=request.user.id).update(last_login=timezone.now())
                visit_time = 300
                cache.set(cache_key, 1, visit_time)

Пояснение:

  • Мы наследуемся от миксина MiddlewareMixin, где используя метод, мы получаем ключ сессии, сохраняем его в кеше, и обновляем дату последнего посещения на сегодняшнюю. Сессия онлайна длится 300 секунд и обновляется при обновлении страницы.

Добавим в __init__.py вызов нашего класса (если вы используете ту же структуру, как у меня)

modules/system/middleware/__init__.py

from modules.system.middleware.activauser import ActiveUserMiddleware

__all__ = ('ActiveUserMiddleware', )

Этот способ использует кэширование. Крайне рекомендую Redis кэширование.

Но сейчас мы воспользуемся просто файловым кэшированием.

Поэтому в корне проекта я создам папку cache.

Далее нам необходимо настроить кэш в settings.py, а также добавить наш новый middleware

backend/settings.py

Добавление middleware

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'modules.system.middleware.ActiveUserMiddleware',
]

Добавление настроек кэша где-нибудь в файле settings.py:

# Cache settings

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': (BASE_DIR / 'cache'),
    }
}

Также добавим метод для получение статуса онлайна в модель профиля пользователя:

modules/system/models/profiles.py

from datetime import date, timedelta

from django.core.validators import FileExtensionValidator
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.urls import reverse
from django.utils import timezone

from modules.system.services.utils import ImageDirectorySave, unique_slugify


class Profile(models.Model):
    user = models.OneToOneField(User, verbose_name='Профиль пользователя', on_delete=models.CASCADE)
    slug = models.SlugField(verbose_name='Персональная ссылка', max_length=255, blank=True, unique=True)
    bio = models.TextField(max_length=500, verbose_name='Информация о себе', blank=True)
    avatar = models.ImageField(
        verbose_name='Аватар профиля',
        blank=True,
        upload_to=ImageDirectorySave('images/avatars/'),
        validators=[FileExtensionValidator(
            allowed_extensions=('png', 'jpg', 'webp', 'jpeg'))
        ]
    )
    date_birthday = models.DateField(verbose_name='Дата рождения', blank=True, null=True)
    following = models.ManyToManyField('self', verbose_name='Подписки', related_name='followers', symmetrical=False, blank=True)

    class Meta:
        """
        Сортировка, название модели в админ панели, таблица в данными
        """
        ordering = ('user',)
        verbose_name = 'Профиль'
        verbose_name_plural = 'Профили пользователей'
        db_table = 'app_profiles'

    def save(self, *args, **kwargs):
        """
        Сохранение параметров модели при их отсутствии заполнения
        """
        if not self.slug:
            self.slug = unique_slugify(self, self.user.username)
        if self.slug:
            self.slug = self.slug.lower()
        super().save(*args, **kwargs)

    def __str__(self):
        """
        Возвращение имени пользователя
        """
        return self.user.username

    @property
    def get_avatar(self):
        """
        Получение аватара при отсутствии загруженного
        """
        if not self.avatar:
            return f'https://ui-avatars.com/api/?size=128&background=random&name={self.user.username}'
        return self.avatar.url

    @property
    def get_age(self):
        """
        Вычисление возраста пользователя
        """
        if self.date_birthday:
            return (date.today() - self.date_birthday) // timedelta(days=365.2425)
        return 'не указан'

    def is_online(self):
        """
        Показывает данные об онлайне
        """
        if self.user.last_login:
            now = timezone.now()
            if now > self.user.last_login + timezone.timedelta(seconds=300):
                return False
            return True
        else:
            return False

    def get_absolute_url(self):
        """
        Ссылка на профиль
        """
        return reverse('profile', kwargs={'slug': self.slug})


@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    """
    Сигнал создания профиля пользователя
    """
    if created:
        Profile.objects.create(user=instance)


@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    """
    Сигнал пересохранения профиля пользователя
    """
    instance.profile.save()

Пояснение:

  • Я добавил метод is_online, остальной код - лишь напоминание о нашей проделанной работы в уроках.
  • В данном методе мы сравниваем дату последнего посещения с текущим временем и возвращаем соответственный результат.

Теперь добавим в шаблон наш статус:

templates/modules/system/profiles/profile-detail.html

{% extends 'main.html' %}
{% load static %}

{% block content %}
    <div class="card border-0 mb-2">
        <div class="card-body">
            <div class="row">
                <div class="col-md-3">
                    <figure>
                        <img src="{{ profile.get_avatar }}" class="img-fluid rounded-0" alt="{{ profile }}">
                    </figure>
                </div>
                <div class="col-md-9">
                     <h5 class="card-title">
                        {{ profile }}
                    </h5>
                    <div class="card-text">
                        <ul>
                            <li>Никнейм: {{ profile.user.username }}</li>
                            <li>Заходил: {{ profile.user.last_login }}</li>
                            <li>Статус: {% if profile.is_online %}<span class="text-success">Online</span>{% else %}<span class="text-danger">Offline</span>{% endif %}</li>
                            <li>Возраст: {{ profile.get_age }}</li>
                            <li>О себе: {{ profile.bio }}</li>
                        </ul>
                        {% if request.user != profile.user and request.user.is_authenticated %}
                            {% if request.user.profile in profile.followers.all %}
                                <button class="btn btn-sm btn-danger btn-following" data-slug="{{ profile.slug }}">
                                    Отписаться от {{ profile }}
                                </button>
                            {% else %}
                               <button class="btn btn-sm btn-primary btn-following" data-slug="{{ profile.slug }}">
                                    Подписаться на {{ profile }}
                                </button>
                           {% endif %}
                        {% endif %}
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="card border-0">
        <div class="card-body">
            <div class="row">
                <div class="col-md-6">
                    <h6 class="card-title">
                        Подписки
                    </h6>
                    <div class="card-text">
                     <div class="row">
                           {% for following in profile.following.all %}
                              <div class="col-md-2">
                               <a href="{{ following.get_absolute_url }}">
                                 <img src="{{ following.get_avatar }}" class="img-fluid rounded-1" alt="{{ following }}"/>
                               </a>
                              </div>
                          {% endfor %}
                     </div>
                    </div>
                </div>
                <div class="col-md-6">
                    <h6 class="card-title">
                        Подписчики
                    </h6>
                    <div class="card-text">
                        <div class="row" id="followersBox">
                           {% for follower in profile.followers.all %}
                              <div class="col-md-2" id="user-slug-{{ follower.slug }}">
                               <a href="{{ follower.get_absolute_url }}">
                                 <img src="{{ follower.get_avatar }}" class="img-fluid rounded-1" alt="{{ follower }}"/>
                               </a>
                              </div>
                          {% endfor %}
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

{% block script %}
    <script src="{% static 'custom/js/profile.js' %}"></script>
{% endblock %}

Добавил:

  •  <li>Статус: {% if profile.is_online %}<span class="text-success">Online</span>{% else %}<span class="text-danger">Offline</span>{% endif %}</li>

Теперь можем смотреть результат на самом сайте:

Зайдем к тому, кого нет сейчас на сайте:

У нас все получилось. Этот статус можно вывести везде, где вам только это необходимо.

Комментарии к статье 0
Комментариев нет
Форма добавления комментария (необходима регистрация)