使用 django 通道在 django 模板中显示 websocket 消息的正确方法是什么?

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

我正在尝试使用渠道和芹菜实时显示来自第三方 api 的股市数据。我正在使用 celery 从 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?&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()

这是我的错误。

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

应该是

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

这里的问题出在你的 JS 代码上。当您使用 querySelector 访问价格时。这没有错。当您有一个 id 可以访问时,您就有一个专门的功能,即 getElementById.

主要错误是,在 HTML 标记中定义一个 id 你不应该使用 #。所以我的建议是这个

像这样做标记

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

然后像这样做 JS 部分

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