Django 频道:将表单数据传递给消费者

Posted

技术标签:

【中文标题】Django 频道:将表单数据传递给消费者【英文标题】:Django channels: pass form data to consumer 【发布时间】:2019-03-10 21:56:57 【问题描述】:

我正在学习 Django,我正在一个网页中工作,我需要为用户提供登录外部服务的可能性。我不能简单地使用传统的 Django 视图系统,否则我会因为简单的刷新而失去连接。出于这个原因,我考虑使用Django Channels。

我现在的问题是如何将数据发送到消费者类?使用tutorial 中给出的consumers.py,我想将表单提交中的数据发送到connect 函数,然后在登录到外部服务正常时进行连接。然后,在那种情况下,我可以使用 clientinstance 和来自这些外部服务的方法。

那么,简而言之,是否可以向消费者发送表单数据?对于敏感数据的安全性,这样可以吗?

from channels.generic.websocket import AsyncWebsocketConsumer
import json

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):

        ######
        ## login to external service
        ######

        #get login data from form submited when the websockted is initiated
        username = ...
        pass = ...

        self.client = Client(username, password)
        if  client:       
            await self.accept()

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

        self.client.send(event['message'])

更新:

To clear the explanation: I can't save the user username and pass of the external service, and that I want to offer the user the possibility to use this [sms service](https://clxcommunications.github.io/sdk-xms-python/tutorial.html) with a text field and phone number.

所以问题是即使我创建了一个表单和用户名和密码来登录(在视图中)

client = clx.xms.Client('myserviceplan', 'mytoken')

然后在下一个请求中,我将丢失 client 实例。这就是我想到Django Channels 的原因。但我不确定这是否是最好的解决方案......

【问题讨论】:

您可以将凭据缓存在浏览器中或作为 cookie。无论如何,如果你真的想使用通道来实现这一点,客户端必须首先通过 websocket 连接到服务器,然后你将他添加到由他的 id 或他独有的东西组成的组中。然后,当他提交表单时,您可以像我在下面所做的那样使用 channel_layer 在消费者中调用一些方法(不连接),该方法获取凭据并在客户端不存在时创建客户端。然后继续向服务发出所需的请求。不过,这是一种非常奇怪的方式 好的,感谢您的建议! 【参考方案1】:

这会对你有所帮助。

consumers.py

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json

class EventConsumer(WebsocketConsumer):
    def connect(self):
        # self.room_name = self.scope['url_route']['kwargs']['room_name']
        # self.room_group_name = 'chat_%s' % self.room_name
        self.room_name = 'event'
        self.room_group_name = self.room_name+"_sharif"
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )
        print(self.room_group_name)
        self.accept()
        print("#######CONNECTED############")

    def disconnect(self, code):
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )
        print("DISCONNECED CODE: ",code)

    def receive(self, text_data=None, bytes_data=None):
        print(" MESSAGE RECEIVED")
        data = json.loads(text_data)
        message = data['message']
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
                "type": 'send_message_to_frontend',
                "message": message
            
        )
    def send_message_to_frontend(self,event):
        print("EVENT TRIGERED")
        # Receive message from room group
        message = event['message']
        # Send message to WebSocket
        self.send(text_data=json.dumps(
            'message': message
        ))

然后从您的应用程序外部/任何地方调用该函数,例如

def event_triger():
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        'event_sharif',
        
            'type': 'send_message_to_frontend',
            'message': "event_trigered_from_views"
        
    ) 
# here 'event_sharif' is your room_group_name as i defined before in consumer
# 'type' is like a command, for which method you wants to trigger in your consumer

更多内容请关注Send message using Django Channels from outside Consumer class

【讨论】:

【参考方案2】:

一般情况下,您可以通过以下方式从外部代码调用消费者中的方法:

from channels.layers import get_channel_layer
channel_layer = get_channel_layer()

await self.channel_layer.send(
            '<channel_name>',
            
                'type': '<method_name>',
            
        )

但正如您所见,这需要您指定只有在客户端连接后才能获得的频道名称。换句话说,您不应该尝试调用连接,而是调用消费者中的其他方法。此外,您的客户端应首先连接到 websocket,然后才能最终访问它。我不完全理解你的用例,但我希望这能给你一个想法

【讨论】:

我的主要问题是我需要发送并保持一个外部服务的实例。总而言之,我想用 django 创建一个 Web 应用程序,它允许用户登录到外部服务,例如 clx sms service。在某些时候,用户将使用用户名填写表单并传递此外部服务,并被重定向到他/她可以使用该服务的另一个页面。但为此,我需要保存实例clientalive。知道我该怎么做吗? PS:self.channel_layer.send() 不起作用,因为要发送的对象不能是不可序列化的。 我不确定我是否了解您以及渠道如何在这里发挥作用。如果用户必须通过您的应用程序向外部服务提供他的登录名和密码,为什么不将其存储并在后续对服务的请求中使用呢?让客户保持活力到底是什么意思?哪个客户?最好在原帖中逐步解释您想要实现的目标以及当前涉及的限制或问题,以便于理解 好的,抱歉解释不好。也许是一个重要的细节:我试图避免保存用户登录名和密码(外部服务)。这就是为什么我需要将实例(self.client)从一个请求记录到另一个请求。这就是为什么我想到Django Channels。不过不确定是否合适…… 刚刚添加了一个额外的解释。请告诉我它是否仍然令人困惑。谢谢!

以上是关于Django 频道:将表单数据传递给消费者的主要内容,如果未能解决你的问题,请参考以下文章

通过 PHP 将 MySQL 数据传递给模态表单

Android:如何将数据传递给子活动?

django将数据传递给javascript的最佳方式

easyui怎么将前台表单数据传递给后台

将默认数据传递给 Vue 表单组件

通过 Redirect 将数据传递给组件