Расширение веб-сокета htmx не отображает серверные сообщения
Я использую приведенную ниже схему для отображения начальных значений модели при загрузке.
consumers.py:
from channels.generic.websocket import WebsocketConsumer
from django.template.loader import render_to_string
from myapp.models import Model1, Model2, Model3, Model4
class DashboardHeaderConsumer(WebsocketConsumer):
def update_dashboard_counts(self):
stats = [
{'name': 'Model1', 'value': Model1.objects.count()},
{'name': 'Model2', 'value': Model2.objects.count()},
{'name': 'Model3', 'value': Model3.objects.count()},
{'name': 'Model4', 'value': Model4.objects.count()},
]
html = render_to_string('dashboard/header-stats.html', {'stats': stats})
self.send(text_data=html)
def connect(self):
self.accept()
self.update_dashboard_counts()
header-stats.html
:
{% for stat in stats %}
<div class="col-sm-6 col-xl-3">
<div class="dashboard-stat rounded d-flex align-items-center justify-content-between p-4">
<div class="ms-3">
<p class="mb-2">{{ stat.name }}</p>
<h6 class="mb-0">{{ stat.value }}</h6>
</div>
</div>
</div>
{% endfor %}
my-template.html
:
{% load static %}
{% block styles %}
<link rel="stylesheet" href="{% static 'css/dashboard.css' %}">
{% endblock %}
<div class="container-fluid pt-4 px-4">
<div class="row g-2 mb-2 stats-wrapper"
hx-ext="ws"
ws-connect="/ws/dashboard/header/"
hx-target=".stats-wrapper"
hx-swap="innerHTML"
>
</div>
<div class="active-tasks-scroll-container">
<div class="row flex-nowrap g-2">
</div>
</div>
</div>
Я ожидаю, что появятся результаты подсчета. Однако, несмотря на то, что сообщение получено и его можно увидеть в разделе "Запрос сетевого веб-сокета", dom пуст. Вот что отображается:
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="UTF-8">
<title>App Title</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/index.css" rel="stylesheet">
<script src="/static/js/bootstrap.bundle.min.js"></script>
<script src="/static/js/htmx.min.js"></script>
<script src="/static/js/htmx-ext-ws%402.0.2"></script>
<style> .htmx-indicator {
opacity: 0
}
.htmx-request .htmx-indicator {
opacity: 1;
transition: opacity 200ms ease-in;
}
.htmx-request.htmx-indicator {
opacity: 1;
transition: opacity 200ms ease-in;
} </style>
</head>
<body>
<div class="content-wrapper" id="content-wrapper">
<div class="container-fluid pt-4 px-4">
<div class="row g-2 mb-2 stats-wrapper" hx-ext="ws" ws-connect="/ws/dashboard/header/"
hx-target=".stats-wrapper" hx-swap="innerHTML">
</div>
<div class="active-tasks-scroll-container">
<div class="row flex-nowrap g-2">
</div>
</div>
</div>
</div>
</body>
</html>
Я перепробовал все, начиная с отправки результата в формате json, добавления идентификатора, добавления hx-swap-oob="beforeend"
, установки hx-receive
, ... ничего не работает.
Я думаю, вы отправляете необработанный HTML-код из Django Channels consumer
self.send(text_data=html)
но HTML-код не содержит .stats-wrapper div, поэтому HTMX понятия не имеет, какую часть DOM заменить.
Объект подкачки ищет .stats-wrapper
, но это не включено в ответ.
Итак, чтобы исправить это, обновите свой header-stats.html шаблон следующим образом:
<div class="row g-2 mb-2 stats-wrapper">
{% for stat in stats %}
<div class="col-sm-6 col-xl-3">
<div class="dashboard-stat rounded d-flex align-items-center justify-content-between p-4">
<div class="ms-3">
<p class="mb-2">{{ stat.name }}</p>
<h6 class="mb-0">{{ stat.value }}</h6>
</div>
</div>
</div>
{% endfor %}
</div>
и если вы не хотите включать .stats-wrapper
в свой ответ (а отправляете только внутреннее содержимое), то сделайте ответ внеполосным:
<div class="row g-2 mb-2 stats-wrapper" hx-swap-oob="true">
{% for stat in stats %}
...
{% endfor %}
</div>
Таким образом, HTMX найдет соответствующий .stats-wrapper
в DOM и заменит его, даже если он не предназначен напрямую.