首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Signals和django频道聊天室

Signals和django频道聊天室
EN

Stack Overflow用户
提问于 2018-05-12 04:21:56
回答 1查看 1.6K关注 0票数 3

嗨,我正在努力让两件事同时工作……

开始使用channels2 chat room示例是可以的,但我想添加一个功能,可以知道房间里有多少人。我通过更新房间模型实现了这一点。

然后我想要有一个仪表板,可以显示当前最受欢迎的房间,我也想用频道更新它。我使用了django signals方法,这种方法可以在没有人使用聊天的情况下更新模型。

但是,当查看仪表板是否在某人加入聊天时更新时,会出现错误。

代码语言:javascript
复制
    2018-05-11 19:19:09,634 - ERROR - server - Exception inside application: You cannot use AsyncToSync in the same thread as an async event loop - just await the async function directly.
  File "/dev/channels_sk/channels-master/channels/consumer.py", line 54, in __call__
    await await_many_dispatch([receive, self.channel_receive], self.dispatch)
  File "/dev/channels_sk/channels-master/channels/utils.py", line 50, in await_many_dispatch
    await dispatch(result)
  File "/dev/channels_sk/channels-master/channels/consumer.py", line 67, in dispatch
    await handler(message)
  File "/dev/channels_sk/channels-master/channels/generic/websocket.py", line 173, in websocket_connect
    await self.connect()
  File "/dev/channels_sk/tables/consumers.py", line 19, in connect
    room.save()
  File "/dev/channels_sk/.env/lib/python3.6/site-packages/django/db/models/base.py", line 729, in save
    force_update=force_update, update_fields=update_fields)
  File "/dev/channels_sk/.env/lib/python3.6/site-packages/django/db/models/base.py", line 769, in save_base
    update_fields=update_fields, raw=raw, using=using,
  File "/dev/channels_sk/.env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 178, in send
    for receiver in self._live_receivers(sender)
  File "/dev/channels_sk/.env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 178, in <listcomp>
    for receiver in self._live_receivers(sender)
  File "/dev/channels_sk/tables/signals.py", line 20, in room_save_handler
    'update': instance.population,
  File "/dev/channels_sk/.env/lib/python3.6/site-packages/asgiref/sync.py", line 34, in __call__
    "You cannot use AsyncToSync in the same thread as an async event loop - "
  You cannot use AsyncToSync in the same thread as an async event loop - just await the async function directly. 

consumers.py

代码语言:javascript
复制
from channels.generic.websocket import AsyncWebsocketConsumer
import json
import time
from .models import Room
from django.db.models import F

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name

        # create room or increment
        room, created = Room.objects.get_or_create(title=self.room_name)
        pop = room.population + 1
        room.population = F('population') + 1
        room.save()

        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

        # send new population to group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
            'type': 'pop_message',
            'population': pop,
            }
        )

    async def disconnect(self, close_code):
        room = Room.objects.get(title=self.room_name)
        pop = room.population - 1
        if room.population == 1:
            if room.permanent == False:
                room.delete()
        else:
            room.population = F('population') - 1
            room.save()

        # send new population to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
            'type': 'pop_message',
            'population': pop,
            }
        )

        # Leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']


        # Send message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
        )

    # Receive message from room group
    async def chat_message(self, event):
        message = event['message']

        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            # 'type': 'chat_message',
            'message': message,
        }))

    # change in room group population
    async def pop_message(self, event):
        content = event['type']
        population = event['population']

        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            # 'type': 'pop_message',
            'content': content,
            'population': population,

        }))


class RoomConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.group_name = 'chat_room_dash'
        print("joined dash room")

        # Join room group
        await self.channel_layer.group_add(
            self.group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        print("left dash room")
        pass

    async def send_message(self, text_data=None):
        print(text_data)
        labels = []
        data = []
        for room in Room.objects.all()[:3]:
            labels.append(room.title)
            data.append(room.population)

        await self.send(text_data=json.dumps(
        {
            'labels': labels,
            'data': data,

        })) 

signals.py

代码语言:javascript
复制
from django.db.models.signals import post_save
from django.dispatch import receiver
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync



from .models import Room


@receiver(post_save, sender=Room)
def room_save_handler(sender, instance, **kwargs):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        'chat_room_dash',
        {
            'type': 'send_message',
            'update': instance.population,
        }
    )

到目前为止

在读取错误时,我尝试了建议的解决方案,方法是将signals.py room_save_handler()更改为async并等待发送到组的消息。

然而,当我手动更新模型或当用户进入聊天室时,这不会发送消息。

我的客户是,当第一个使用者调用room.save()时,room_save_handler()也会被调用,这意味着在异步调用中有一个异步调用。

任何帮助都是最好的!

EN

回答 1

Stack Overflow用户

发布于 2019-02-27 23:06:39

我也有同样的问题,我已经在下面的way中解决了它

代码语言:javascript
复制
import asyncio

from django.db.models.signals import post_save
from django.dispatch import receiver
from channels.layers import get_channel_layer


from .models import Room


@receiver(post_save, sender=Room)
def room_save_handler(sender, instance, **kwargs):
    channel_layer = get_channel_layer()
    loop = asyncio.get_event_loop()

    coroutine = async_to_sync(channel_layer.group_send)(
        'chat_room_dash',
        {
            'type': 'send_message',
            'update': instance.population,
        }
    )
    loop.run_until_complete(coroutine)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50299749

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档