如何使用 Django 通道将新创建的数据推送到客户端而不重新加载和不完全改变现有的普通视图代码

pre*_*ast 2 django django-models websocket django-rest-framework django-channels

嘿伙计们,我对 django 和 django 频道很陌生。我有一个关于渠道的小疑问。例如,如果我有一个帖子模型并且我创建了一个帖子,为了让用户查看帖子,他们需要重新加载页面或者我们需要将他们重定向到列表页面以查看所有帖子。

如果我想将新创建的帖子推送到前端或客户端而不让他们重新加载页面怎么办?我们可以为此使用渠道吗?如果我们为此目的使用通道,我们是否需要重写我们在普通视图中编写的所有代码,或者添加一个片段代码,例如在创建和运行async函数时发送信号就可以解决问题?实施起来难吗?

谢谢

Chi*_*ali 5

如果我想将新创建的帖子推送到前端或客户端而不让他们重新加载页面怎么办?
是的,但需要注意的是,如果用户(在客户端上)在 <post_list> 页面上,则您必须缓存在此之前编写的所有帖子。这对于一个小项目来说不是问题,但如果他们的帖子太多,加载会花费太多时间。

我们可以为此使用渠道吗?是的

如果我们为此目的使用通道,我们是否需要重写我们在普通视图中编写的所有代码,或者添加一个片段代码,例如在创建和运行异步函数时发送信号就可以解决问题?
是和否,因为您使用了 [django-rest-framework(DRF)],所以 rest-framework 只能在 HTTP 协议上工作;当您使用 websockets 时,您使用的是 WS 协议,从而处理事件 django-channels 拥有消费者,就像 django 和 DRF 中的视图一样。但是您可以(为了保持代码的健壮性而应该)使用您为 [django-rest-framework] 编写的序列化程序。

为了证明这一点,在用户写了一篇文章并且你在你的 django-channel AsyncConsumer 上收到它的场景中,你可以使用这样的东西:-

from channels.db import database_sync_to_async
@database_sync_to_async
    async def save_post(self, data):
        serializer = PostSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        x = serializer.create(serializer.validated_data)#this will create the post
        return PostSerializer(x).data #this will return the serialized post data
Run Code Online (Sandbox Code Playgroud)

由于 django-channels AsyncConsumer 将所有事件写入异步函数并且保存新帖子是一个同步函数,我们需要使用“@database_sync_to_async”;(确保在调用 save_post 函数时使用 await-keyword)。

要回答问题的后半部分,您可以使用 django-signals 吗?是的,修改上面的代码以调用该 django-signal 而不是使用上面“save_post”函数中的序列化程序,您可以序列化 django-signals 中的数据。但我相信上述方法可以解决问题。

根据我的理解,我相信您想通知用户关于每个用户都应该连接到同一个频道组的新帖子,并且一旦 save_post 函数完成,在该组中发送一个带有通知的事件。

#inside the signals.py file
from .models.py import <Post-model>
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 #since everything in django
                                       #is running synchronously.

"""
when the post gets created; the below receiver function would run.
"""
@receiver(post_save,sender=<Post-model>)
def notify_new_post(sender,instance,created,**kwargs)
    if created:
        channel_layer = get_channel_layer()
        async_to_sync(channel_layer.group_send)(
            group=<group_name>,#the group/room that will receive the broadcast
            message= {
                'type':"<name of the event>",
                'payload':{<whatever notification you want to send>}
                #before writing that payload make sure what type of 
                #channels you are using if you are using a 
                #"AsyncWebsocketConsumer" the payload should be in the 
                #appropriate type thereby use json.dumps to convert it to JSON.
                #if you are using "AsyncJsonWebsocketConsumer" then you don't 
                #have to do it [this is just for precautionary].
            }
)

Run Code Online (Sandbox Code Playgroud)

希望这会有所帮助,如果不是继续在这个线程上提问。