Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display an update that is pushed from the server to the webpage without a refresh?

I am using Django 1.10 as the backend of a warehousing app we built.

I am adding another new feature where a webpage that will be displayed on a giant monitor. This webpage will show nothing except for 1 giant number.

I have a RFID device that once detects a RFID tag, will send a http request to my Django server.

When that happens, I want the number from the RFID tag to be displayed on the webpage mentioned earlier.

I have read briefly about socket.io but I want to as much as possible keep within the Django universe. I have read briefly about Django Channels as well.

My questions are:

  1. should I use Django Channels for this use case?
  2. if so, how do i do that with my use case above?
like image 832
Kim Stacks Avatar asked Feb 15 '17 01:02

Kim Stacks


1 Answers

It really depends on the usage of the information you're displaying, if you don't need that number to be in real-time then you can opt for the regular AJAX poll once every X seconds like mentionned in zwer's comment.

Now if you need that number to be in real-time, then you should go for websockets and django channels, it's really easy to setup a code base that does what you want.

Assuming you installed django channels and configured your settings.

First you need to setup the consumers.py and routing.py logic that manages the websockets (think of those as views.py and urls.py but for websocket logic).

consumers.py

from channels import Group
from channels.auth import channel_session_user_from_http, channel_session_user


@channel_session_user_from_http
def ws_add(message):
    # Authenticates the client
    # ASGI WebSocket packet-received and send-packet message types
    # both have a "text" key for their textual data.
    message.reply_channel.send({
        "accept": True,
    })
    Group("rfid-group").add(message.reply_channel)


@channel_session_user
def ws_message(message):
    # You can process messages you receive from the socket here
    # Apply w/e logic validation


@channel_session_user
def ws_disconnect(message):
    Group("rfid-group").discard(message.reply_channel)

routing.py

from channels.routing import route
from .consumers import ws_message, ws_add, ws_disconnect

routing_routing = [
    route("websocket.connect", ws_add),
    route("websocket.receive", ws_message),
    route("websocket.disconnect", ws_disconnect),
]

Now you need to write the front-end websocket logic:

<script>
    socket = new WebSocket("ws://" + window.location.host);
    socket.onmessage = function(e) {
        console.log("Message received");
        // Process the received number here
        console.log(e.data);
    }
</script>

This will establish a websocket connection, subscribes the client to a group called "rfid-group", now any message sent to that Group will be echoed to all subscribers of that Group, this can handle multiple clients.

Now we need the part that will listen to a request from the rfid device, process it, and send the result to the display, this should be a simple view as the RFID device will send regular HTTP information.

from django.http import HttpResponse
from channels import Group


def rfid_processor(request):
    '''
      Consider authenticating your rfid_num producer to prevent
      someone messing with your api
    '''
    rfid_num = request.GET.get("rfid", "")
    if rfid_num:
        Group("rfid-group").send({"text": rfid_num})
        return HttpResponse(status=200)

    return HttpResponse(status=500)

Hook it to a url:

from app.views import rfid_processor
urlpatterns = [
    url(r'^rfid/$', rfid_processor),
]

This is all you need to setup a minimal working django channels project that will echo the number received from the RFID device to the display screen(s).

Hope this helps.

like image 96
HassenPy Avatar answered Nov 15 '22 04:11

HassenPy