您现在的位置是:首页 > 学无止境 > Python 网站首页学无止境
Django Channels 实现点对点实时聊天(方法二)
- Python
- 2018年10月31日 22:05
- 3160已阅读
- 25
在前面一篇博客中,提到了一种完全依赖websocket来传递消息的实时聊天方法。在这里,我们再介绍另一种方法,也是依赖了websocket,但是在这里websocket起到的作用和消息推送一模一样。具体方法如下
开始方法与上一篇文章类似,新建一个consumers.py文件,
class PushConsumer(AsyncWebsocketConsumer):
# chats = dict()
async def connect(self):
await self.channel_layer.group_add(self.group_name, self.channel_name)
# 创建连接时调用
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(
self.group_name,
self.channel_name
)
# PushConsumer.chats[self.group_name].remove(self)
# print(PushConsumer.chats)
async def push_message(self, event):
print(event)
await self.send(text_data=json.dumps({
"data": event['event']
}))
大家看一下可以发现,其实代码和上一篇文章中推送功能的PushConsumer代码一致。然后再在models.py文件里面新增一个Message模块,借助django的signals模块,每当有一条消息新建时,就会自动把这条消息的id实时推送给消息发送者和消息接收者。
# 聊天记录
class Messages(models.Model):
# 信息发送者
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='message_sender')
# 信息接收者
receiver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='message_receiver')
# 信息内容
body = models.CharField(max_length=1024, verbose_name='message_body')
# 发送时间
created = models.DateTimeField(auto_now_add=True)
# 状态
status = models.BooleanField(default=False)
def __str__(self):
return self.body
class Meta:
verbose_name = 'message'
verbose_name_plural = 'messages'
ordering = ('-created',)
# 消息推送
def push(username, event):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
username,
{
"type": "push.message",
"event": event
}
)
@receiver(post_save, sender=Messages)
def post_application_notice(sender, instance=None, created=False, **kwargs):
entity = instance
if created:
push(entity.sender.username, {'type': 5, 'text': entity.id})
push(entity.receiver.username, {'type': 5, 'text': entity.id})
每一位用户都连接到了一个以自己username作为识别的websocket route,具体route形式为 url(r'^push/(?P<username>[0-9a-z]+)/$', consumers.PushConsumer) 这样每当用户接收到type为5的websocket消息时,就明白这是一条聊天信息,然后就可以请求一下消息详情的api,获取这条消息。
# 获取某一条消息
class MessageDetailView(APIView):
permission_classes = (IsAuthenticated,)
authentication_classes = (MyAuthentication,)
serializer_class = MessageDetailSerializer
def get(self, request, pk):
message = Messages.objects.filter(Q(receiver=request.user) | Q(sender=request.user))
try:
message = message.get(id=pk)
# print(MessageDetailSerializer(message))
except Messages.DoesNotExist:
raise NotFound('60001Not found the message.')
else:
msg = Response({
'error': '0',
'data': MessageDetailSerializer(message).data,
}, HTTP_200_OK)
return msg
就这样,一种点对点的实时聊天就完成了。
完善这功能还有很多方面,例如在消息建立时推送给接收者的不仅仅是消息的id,还有发送者;在进入一个聊天界面时可以获取最近的15条聊天记录;具体的完善方式在这里就不一一列举的,因为并不是很难,并且也不涉及到websocket,各位可以自行添加或修改。
版权声明:本文为博主原创文章,转载时请注明来源。https://blog.thinker.ink/passage/16/