Как отправлять уведомления, всем online-пользователям?

Для отправки уведомлений всем online-пользователям в Django, вам понадобится использовать механизм слежения за состоянием пользователей, такой как WebSocket или Long Polling, и соответствующим образом настроить систему уведомлений.

Первым шагом будет настройка и использование WebSocket в Django приложении. Для этого вы можете использовать библиотеку Channels, которая позволяет использовать протокол WebSocket в Django. Чтобы начать, вам нужно будет установить Channels и настроить его в вашем приложении.

1. Установите Channels при помощи pip:

$ pip install channels

2. В вашем файле settings.py добавьте Channels в список установленных приложений:

INSTALLED_APPS = [
    ...
    'channels',
    ...
]

3. Зарегистрируйте новый маршрут WebSocket в файле myapp/routing.py:

from django.urls import path
from myapp import consumers

websocket_urlpatterns = [
    path('ws/notification/', consumers.NotificationConsumer.as_asgi()),
]

4. Создайте файл myapp/consumers.py, где будет храниться ваш WebSocket consumer:

from channels.generic.websocket import AsyncWebsocketConsumer
import asyncio

class NotificationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        # обрабатывайте входящие сообщения
        pass

    async def send_notification(self, event):
        # отправляйте уведомления всем online-пользователям
        pass

5. Настройте ваш сервер для поддержки WebSocket. Например, для использования Channels с сервером Daphne, вы можете запустить сервер следующим образом:

$ daphne myproject.asgi:application --websocket-port 8001

Теперь у вас есть рабочий механизм WebSocket в Django приложении. Следующим шагом будет добавление логики отправки уведомлений всем online-пользователям.

1. В вашем приложении определите класс UserStatus, который будет отслеживать состояние пользователя:

from django.contrib.auth.models import User
from django.db import models

class UserStatus(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    is_online = models.BooleanField(default=False)

2. Создайте сигналы для отслеживания изменений состояния пользователя. В вашем файле myapp/signals.py:

from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from myapp.models import UserStatus

@receiver(post_save, sender=User)
def update_user_status(sender, instance, created, **kwargs):
    if created:
        UserStatus.objects.create(user=instance)
    instance.userstatus.save()

3. Обновите ваш файл myapp/apps.py чтобы подключить сигналы:

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'myapp'

    def ready(self):
        import myapp.signals

4. В myapp/consumers.py добавьте функцию send_notification для отправки уведомлений всем online-пользователям:

from asgiref.sync import async_to_sync
import json

class NotificationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()
        await self.channel_layer.group_add('online_users', self.channel_name)
        user = self.scope["user"]
        user.userstatus.is_online = True
        user.userstatus.save()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard('online_users', self.channel_name)
        user = self.scope["user"]
        user.userstatus.is_online = False
        user.userstatus.save()

    async def receive(self, text_data):
        # обрабатываем входящие сообщения
        pass

    async def send_notification(self, event):
        # Отправляем уведомление всем online-пользователям
        message = event['message']
        await self.send(text_data=json.dumps({
            'type': 'notification',
            'message': message
        }))

    @staticmethod
    @receiver(user_logged_in)
    def on_user_logged_in(sender, request, user, **kwargs):
        channel_layer = get_channel_layer()
        async_to_sync(channel_layer.group_send)(
            'online_users',
            {
                'type': 'send_notification',
                'message': f'Пользователь {user.username} вошел в систему.'
            }
        )

    @staticmethod
    @receiver(user_logged_out)
    def on_user_logged_out(sender, request, user, **kwargs):
        channel_layer = get_channel_layer()
        async_to_sync(channel_layer.group_send)(
            'online_users',
            {
                'type': 'send_notification',
                'message': f'Пользователь {user.username} вышел из системы.'
            }
        )

Теперь, при каждом входе пользователя в систему и выходе из нее, будет отправляться уведомление всем online-пользователям через WebSocket. Вы можете дополнить логику вашего consumer'а NotificationConsumer для обработки различных типов уведомлений и применять их при необходимости.

Важно отметить, что в приведенном выше коде я использовал mix из синхронного и асинхронного Django Channels. Если вы хотите использовать полностью асинхронную версию Channels, вам нужно будет использовать AsyncJsonWebsocketConsumer вместо AsyncWebsocketConsumer и асинхронные версии сигналов Django.

В итоге, с помощью механизмов WebSocket и логики отслеживания состояния пользователей, вы можете отправлять уведомления всем online-пользователям в Django приложении.