Reputation: 41
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
Reputation: 41
This was my mistake.
<p id="#price">{{ text }}</p>
Should be
<p id="price">{{ text }}</p>
Upvotes: 1
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