Отправка сообщения одному пользователю с помощью django-каналов
Я пробовал django-каналы включая чтение документов и игру с примерами.
Я хочу иметь возможность отправлять сообщение одному пользователю, которое запускается при сохранении нового экземпляра в базе данных.
мой вариант использования создает новое уведомление (через задачу сельдерея), и как только уведомление сохранено, отправка этого уведомления одному пользователю.
Это звучит так, как будто это возможно (из django-каналы docs)
...решающая часть заключается в том, что вы можете запустить код (и так отправить каналы) в ответ на любое событие - и это включает в себя те, которые вы создавать. Вы можете вызвать на модели сохраняет, на других входящих сообщениях, или из путей кода внутри представлений и форм.
однако, читая документы дальше и играя с django-примеры каналов, Я не вижу, как я могу это сделать. Привязка данных и примеры liveblog демонстрируют отправку в группу, но я не вижу, как просто отправить одному пользователю.
любые предложения были бы очень признательны.
5 ответов
расширение ответа @Flip о создании группы для этого конкретного пользователя.
в вашей функции python в вашей функции ws_connect вы можете добавить этого пользователя в группу a только для них:
consumers.py
from channels.auth import channel_session_user_from_http,
from channels import Group
@channel_session_user_from_http
def ws_connect(message):
if user.is_authenticated:
Group("user-{}".format(user.id)).add(message.reply_channel)
чтобы отправить этому пользователю сообщение из вашего кода python:
мой view.py
import json
from channels import Group
def foo(user):
if user.is_authenticated:
Group("user-{}".format(user.id)).send({
"text": json.dumps({
"foo": 'bar'
})
})
если они подключены, они получат сообщение. Если пользователь не подключен к websocket он будет молча терпеть неудачу.
вам также необходимо убедиться, что вы подключаете только одного пользователя к группе каждого пользователя, иначе несколько пользователей могут получить сообщение, предназначенное только для конкретного пользователя.
посмотрите на примеры каналов django, особенно multichat для реализации маршрутизации создайте соединение websocket на стороне клиента и настройте django_channels.
убедитесь, что вы посмотрите на Django каналы docs.
небольшое обновление, так как группы работают по-разному с каналами 2, чем с каналами 1. Больше нет группового класса, как уже упоминалось здесь.
новый API групп документирован здесь. См. также здесь.
что работает для меня:
# Required for channel communication
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
def send_channel_message(group_name, message):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'{}'.format(group_name),
{
'type': 'channel_message',
'message': message
}
)
Не забудьте определить метод для обработки типа сообщения в потребителе!
# Receive message from the group
def channel_message(self, event):
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps({
'message': message
}))
лучший подход-создать группу для этого конкретного пользователя. Когда ws_connect вы можете добавить этого пользователя в Group("%s" % <user>).add(message.reply_channel)
Примечание: мой url websocket
ws://127.0.0.1:8000/<user>
чтобы расширить ответ @luke_aus, если вы работаете с ResourceBindings, вы также можете сделать так, чтобы только пользователи, "владеющие" объектом, получали обновления для них:
как и @luke_aus answer, мы регистрируем пользователя в его собственной группе, где мы можем публиковать действия (update
, create
) и т. д., которые должны быть видны только этому пользователю:
from channels.auth import channel_session_user_from_http,
from channels import Group
@channel_session_user_from_http
def ws_connect(message):
Group("user-%s" % message.user).add(message.reply_channel)
теперь мы можем изменить соответствующую привязку, чтобы она публиковала изменения только в том случае, если Связанный объект принадлежит этому пользователь, предполагая такую модель:
class SomeUserOwnedObject(models.Model):
owner = models.ForeignKey(User)
теперь мы можем привязать эту модель к нашей группе пользователей, и все действия (обновление, создание и т. д.) будут опубликованы только одному пользователю:
class SomeUserOwnedObjectBinding(ResourceBinding):
# your binding might look like this:
model = SomeUserOwnedObject
stream = 'someuserownedobject'
serializer_class = SomeUserOwnedObjectSerializer
queryset = SomeUserOwnedObject.objects.all()
# here's the magic to only publish to this user's group
@classmethod
def group_names(cls, instance, action):
# note that this will also override all other model bindings
# like `someuserownedobject-update` `someuserownedobject-create` etc
return ['user-%s' % instance.owner.pk]
на каналы 2, вы можете сохранить self.channel_name
в методе db on connect, который является определенным хэшем для каждого пользователя. документации
from asgiref.sync import async_to_sync
from channels.generic.websocket import AsyncJsonWebsocketConsumer
import json
class Consumer(AsyncJsonWebsocketConsumer):
async def connect(self):
self.room_group_name = 'room'
if self.scope["user"].is_anonymous:
# Reject the connection
await self.close()
else:
# Accept the connection
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
print( self.channel_name )
последняя строка возвращает что-то вроде specific.WxuYsxLK!owndoeYTkLBw
этот конкретный хэш вы можете сохранить в таблице пользователя.