maoying
maoying

Reputation: 41

What's the correct way to get websocket message do display in django template using django channels?

I'm trying to display stock market data from a third party api in realtime using channels and celery. I'm using celery to get data from the api and channels to receive and send the data to the client.

My issue is that the data isn't rendering in the template and my python and javascript aren't showing any errors so I have no idea what's wrong. Help would be appreciated.

ignore commented out code in snippets.

tasks.py

import requests
from celery import shared_task
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync


channel_layer = get_channel_layer()

@shared_task
def get_stock_info ():

    # request.session['sym'] = sym
    payload = {'symbol': 'nvda'}
    # r = requests.get('https://api.twelvedata.com/time_series?&interval=1min&apikey=xxxxxxxxx',
    #  params=payload)
    r = requests.get('https://api.twelvedata.com/price?apikey=xxxxxxxxx',
     params=payload)
    res = r.json()
    price = res['price']

    async_to_sync(channel_layer.group_send)('stocks', {'type': 'send_info', 'text': price})

    

consumers.py

from channels.generic.websocket import AsyncWebsocketConsumer

class StockConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.channel_layer.group_add('stocks', self.channel_name)
        await self.accept()

    async def disconnect(self):
        await self.channel_layer.group_discard('stocks', self.channel_name)

    async def send_info(self, event):
        msg = event['text']

        await self.send(msg)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <title>Document</title>
</head>
<body>
   
  <p id="#price">{{ text }}</p>
  <p id="description">{{ res.Description }}</p>
  


  <script>
    var socket = new WebSocket('ws://localhost:8000/ws/stock_info/');
  
    socket.onmessage = function(event){
      var price = event.data;
  
      document.querySelector('#price').innerText = price;
  
  
    }
  </script>
  
</body>


</html>

routing.py

from django.urls import path
from .consumers import StockConsumer

ws_urlpatterns = [
    path('ws/stock_info/', StockConsumer.as_asgi())
]

celery.py

import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'stockwatch.settings')

app = Celery('stockwatch')
app.config_from_object('django.conf:settings', namespace='CELERY')

# app.conf.beat_schedule = {
#     'get_info_1s': {
#         'task': 'stock_info.tasks.get_stock_info',
#         'schedule': 3.0
#     }
# }

app.autodiscover_tasks()

Upvotes: 2

Views: 1255

Answers (2)

maoying
maoying

Reputation: 41

This was my mistake.

<p id="#price">{{ text }}</p>

Should be

<p id="price">{{ text }}</p>

Upvotes: 1

moshfiqrony
moshfiqrony

Reputation: 4733

The problem here is with your JS code. When you are accessing the price using querySelector. There is no fault in it. When you have a id to access, you have a dedicated function for it which is getElementById.

The main fault is, in the HTML markup to define a id you should not use the #. So my recommendation will be this

Do the markup like this

<p id="price">{{ text }}</p>

and do the JS part like this

document.getElementById('price').innerText = price;

Upvotes: 0

Related Questions