How can I make SSE with Python (Django)?

后端 未结 2 1885
情话喂你
情话喂你 2020-12-17 21:28

I have two different pages, one (A) that displays data taken from a model object, and one (B) that changes its fields. I would like that when the post data is sent from B to

相关标签:
2条回答
  • 2020-12-17 22:13

    This is working example from w3schools in Django:

    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):

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

    That's it, simple as that.

    0 讨论(0)
  • 2020-12-17 22:22

    After reading this, I think I understood the whole thing (please comment if I’m wrong).



    Django does NOT natively support keep-alive connections. 
This means, when the client gets the message from the server, the connection is immediately closed after (like any classic HTTP request/response cycle).

    
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).



    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).

    

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.


    0 讨论(0)
提交回复
热议问题