简体   繁体   English

如何使用 Python (Django) 制作 SSE?

[英]How can I make SSE with Python (Django)?

I have two different pages, one (A) that displays data taken from a model object, and one (B) that changes its fields.我有两个不同的页面,一个 (A) 显示从模型对象中获取的数据,另一个 (B) 更改其字段。 I would like that when the post data is sent from B to the server, the server changes the values in A. What is the best way to do it?我希望当发布数据从 B 发送到服务器时,服务器会更改 A 中的值。最好的方法是什么?

This example could work for me but it's in PHP... there is a way to replicate it whit Python?这个例子对我有用,但它是用 PHP 编写的……有没有办法用 Python 复制它? https://www.w3schools.com/html/html5_serversentevents.asp https://www.w3schools.com/html/html5_serversentevents.asp

This is working example from w3schools in Django:这是 Django 中 w3schools 的工作示例:

template模板

<!DOCTYPE html>
<html>
<body>

<h1>Getting server updates</h1>
<div id="result"></div>

<script>
if(typeof(EventSource) !== "undefined") {
  var source = new EventSource("stream/");
  source.onmessage = function(event) {
    document.getElementById("result").innerHTML += event.data + "<br>";
  };
} else {
  document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>

</body>
</html>

views意见

import datetime
import time
from django.http import StreamingHttpResponse

def stream(request):
    def event_stream():
        while True:
            time.sleep(3)
            yield 'data: The server time is: %s\n\n' % datetime.datetime.now()
    return StreamingHttpResponse(event_stream(), content_type='text/event-stream')

urls网址

urlpatterns = [
    path('stream/', views.stream, name='stream')
]

Update:更新:

If you want to manage your notifications you can create the model like:如果您想管理您的通知,您可以创建如下模型:

from django.db import models

class Notification(models.Model):
    text = models.CharField(max_length=200)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    sent = models.BooleanField(default=False)

Then create the view that is looking for the first unsent notification and sends it:然后创建寻找第一个未发送通知的视图并发送它:

@login_required
def stream(request):
    def event_stream():
        while True:
            time.sleep(3)
            notification = Notification.objects.filter(
                sent=False, user=request.user
            ).first()

            text = ''

            if notification:
                text = notification.text
                notification.sent = True
                notification.save()

            yield 'data: %s\n\n' % text

    return StreamingHttpResponse(event_stream(), content_type='text/event-stream')

And the send_notification function that creates an entry in the Notification model (just call this function from anywhere in your code):以及在Notification模型中创建条目的send_notification函数(只需从代码中的任何位置调用此函数):

def send_notification(user, text):
    Notification.objects.create(
        user=user, text=text
    )

That's it, simple as that.就是这样,就这么简单。

After reading this , I think I understood the whole thing (please comment if I'm wrong).看完这篇,我想我明白了整件事(如果我错了,请评论)。

Django does NOT natively support keep-alive connections. Django 本身不支持保持活动连接。 This means, when the client gets the message from the server, the connection is immediately closed after (like any classic HTTP request/response cycle).这意味着,当客户端从服务器获取消息时,连接会立即关闭(就像任何经典的 HTTP 请求/响应周期一样)。

What's different with text/event-stream request, is that the client automatically tries to reconnect to the server every second (the length can be changed with a retry parameter).text/event-stream请求不同的是,客户端每秒自动尝试重新连接到服务器(可以使用retry参数更改长度)。

Unfortunately, it seems using SSE in that case has no interest since it has the same con's that polling (ie. a request/response cycle occurs each X seconds).不幸的是,在这种情况下使用 SSE 似乎没有兴趣,因为它具有与轮询相同的缺点(即每 X 秒发生一个请求/响应周期)。

As expected and mentioned in other answers, I would need django-channels to create a persistent connection that prevent HTTP request/response overheads and ensure the message is sent immediately.正如预期并在其他答案中提到的那样,我需要 django-channels 来创建一个持久连接,以防止 HTTP 请求/响应开销并确保立即发送消息。

As mentioned in other answers, you will need to use Django Channels to properly handle asynchronous communication without tying up threads.正如其他答案中提到的,您将需要使用 Django Channels 来正确处理异步通信,而不会占用线程。

For an example, see the django-eventstream library which uses Channels to implement SSE.例如,请参阅使用 Channels 实现 SSE的 django-eventstream 库

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM