Как правильно отобразить сообщение websocket в шаблоне django с помощью каналов django?

#python #django #django-channels

Вопрос:

Я пытаюсь отображать данные о фондовом рынке из стороннего api в режиме реального времени, используя каналы и сельдерей. Я использую сельдерей для получения данных из api и каналов для получения и отправки данных клиенту.

Моя проблема в том, что данные не отображаются в шаблоне, а мой python и javascript не показывают никаких ошибок, поэтому я понятия не имею, что не так. Помощь была бы признательна.

игнорируйте закомментированный код во фрагментах.

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?amp;interval=1minamp;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()
 

Комментарии:

1. Пожалуйста, убедитесь, что вы никогда не публикуете свои личные ключи API на общедоступном форуме. Перейдите в Twelvedata и удалите/обновите свои ключи как можно скорее.

2. @Фелипе спасибо, я этого не знал, но это имеет смысл.

Ответ №1:

Это была моя ошибка.

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

Должно быть

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

Ответ №2:

Проблема здесь в вашем JS-коде. Когда вы получаете доступ к цене с помощью querySelector . В этом нет никакой вины. Когда у вас есть идентификатор для доступа, у вас есть специальная функция для него, которая есть getElementById .

Основная ошибка заключается в том, что в HTML-разметке для определения идентификатора вы не должны использовать #. Поэтому моя рекомендация будет такой

Сделайте разметку вот так

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

и сделайте часть JS вот так

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