如何将渠道和 DRF 整合在一起

Gui*_*tia 5 python django django-rest-framework django-channels

我目前正在尝试创建一个后端服务器来与一些使用 websocket 的客户端进行通信。客户端向后端发出一些请求,后端通过消费者直接响应客户端。

另外,我有一个需要向客户端发送一些请求的 API。它必须通过消费者打开的套接字。我正在为 API 使用 Django Rest Framework。所以我现在有 2 个应用程序。一种用于消费者,一种用于 API。我想知道这是否是正确的方法。

这实际上是我现在正在考虑的代码:

# mybackendapp/consumers.py

class MyConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.client_id = self.scope['url_route']['kwargs']['client_id']
        # This line I don't get it very well. It comes from:
        # [channels doc: single channels][1]
        # I don't know if I should create the Clients myself or if it's 
        # created automatically
        Clients.objects.create(channel_name=self.channel_name, 
                               self.client_id)
        self.accept()

    async def disconnect(self):
         Clients.objects.filter(channel_name=self.channel_name).delete()

    async def receive(self, text_data):
        self.recv_data = json.loads(text_data)
        if self.recv_data[0] == CLIENT_REQUEST:
            self.handler = ClientRequestHandler(self.client_id, 
                                                self.recv_data)
            await self.handler.run()
            self.sent_data = self.handler.response
            self.send(self.sent_data)
        elif self.recv_data[0] == CLIENT_RESPONSE:
            self.handler = ClientResponseHandler(self.client_id,
                                                 self.recv_data)
            channel_layer = get_channel_layer()
            # Here I'm not sure but I may have several API requests so
            # several row with the same client_id.
            # I welcome info on how to deal with that.
            api_channel_name = self.another_handler.ext_channel_name
            channel_layer.send(api_channel_name, {
                "text_data": self.handler.response,
            })

    async def message_from_api(self, event):
        self.api_channel_name = event['channel_name_answer']
        # this line is for hiding the fact that I'm only manipulating data
        # to send it to a correct format to the socket
        self.another_handler = ExternalDataHandler(event['json_data'])
        query_to_client = another_handler.get_formatted_query()
        self.send(query_to_client)
Run Code Online (Sandbox Code Playgroud)

在接收中,此消费者以不同方式处理来自客户端的消息,具体取决于它是由客户端还是由其余 API 发起。你可以看到CLIENT_REQUESTCLIENT_RESPONSE常量。现在从 API 视图:

# myapi/views.py

from channels.layers import get_channel_layer

def my_api_view(request, client_id):
    channel_layer = get_channel_layer()
    if request.method == 'POST':
        ext_request_data_json = request.data
        client_channel_name = Clients.objects.get(
            client_id=client_id).channel_name
        # I don't know what type is listen_channel_name. I assume it's str
        listen_channel_name = async_to_sync(channels_layers.new_channel)()
        async_to_sync(channel_layer.send)(
            client_channel_name, {
                'type': 'message.from.api',
                'json_data': ext_request_data_json,
                'channel_name_answer': listen_channel_name
            }
        )
        received_msg = channel_layer.receive(listen_channel_name)
Run Code Online (Sandbox Code Playgroud)

我相信这段代码应该可以工作。我想知道这是否是正确的方法。

pho*_*nix 0

视为djangochannelsrestframework可能的替代解决方案。

Django Channels Rest Framework 提供了一个类似 DRF 的接口来构建channels-v3websocket 消费者。