python - 使用 WSGI 从 db 向客户端发送模型更新
问题描述
通知客户他们正在查看的模型表发生变化的最轻量级的方法是什么?
我使用 Django Rest Framework 设置了一个 API,为客户提供模板化的项目表,并允许他们即时更改买家。
目前,我使用带有 setTimeout 的重复 jQuery AJAX 请求 2 秒。即使没有更改,这也会发送大量请求和数据,并且网页大小不断增长。
我不得不禁用缓存,因为某些用户可能有 IE11。
我开始寻找一种将更新推送到客户端的方法,并开始探索 Django Channels 和 Server-Sent-Events。
Django 频道
- 构建了演示聊天应用程序
- 非常快
- 我所有的目标浏览器都支持Websocket
- 对于我想要实现的目标来说,这似乎有点矫枉过正。
- 很多配置
- 需要 Redis 或其他一些数据存储
- 我真的不需要双向沟通
- 我的应用程序托管在 Pythonanywhere 上,它不允许 ASGI 并且似乎没有任何计划这样做(1、2)。
服务器发送事件
- 关于如何为 Django 配置它的信息很少
- 在 IE11 或 Edge 中没有原生支持,但有可用的 polyfill
- 从 stackoverflow找到并测试了一个工作示例,但不确定它在做什么。网页每 5 秒更新一次,不知道在哪里控制。
- 很少的设置,看起来几乎是神奇的
- 似乎将它与 Django 中的post_save 信号一起使用是理想的,但我不知道如何设置它。
当前,基于 AJAX 的设置:
模型.py
...
...
class Buyer(models.Model):
name = models.CharField(unique=True, max_length = 20)
class Item(models.Model):
name = models.CharField(unique=True, max_length = 50)
active = models.BooleanField(default=True)
bought_by = models.ForeignKey(Buyer, null=True, blank=True, to_field="name",)
视图.py
...
...
class ItemViewSet(viewsets.ModelViewSet):
queryset = models.Item.objects.select_related("bought_by")
serializer_class= serializers.ItemSerializer
filterset_fields = ("bought_by")
renderer_classes = [renderers.JSONRenderer, renderers.BrowsableAPIRenderer, renderers.TemplateHTMLRenderer]
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if request.accepted_renderer.format == "html":
items = list()
for item in queryset:
items.append({"serializer": self.get_serializer(item), "item": item})
return Response(
{
"items_info": items,
"style": {"template_pack": "rest_framework/inline/"},
},
template_name="myapp/items_list.html",
)
else:
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
...
...
(修改了列表方法以使客户可以编辑每个项目)
handler.js
...
...
$.ajaxSetup({
cache: false
});
var tableUpdater = null;
var updateRequest = null;
// helper that can be called to cancel active timer/ajax in the
// case of interaction with buttons/selects on the page or
// in the case of a new request
function stopUpdate() {
if (tableUpdater || updateRequest) {
clearTimeout(tableUpdater);
updateRequest.abort();
}
}
// Update data table
function tableUpdate() {
stopUpdate();
updateRequest = $.ajax({
type: "GET",
url: "myapp/items/?format=html",
success: function(data) {
$("#activeRequests").html(data);
// schedule another AJAX request
tableUpdater = setTimeout(tableUpdate, 2000);
}
});
}
...
...
解决方案
我曾尝试使用 Django Channels,但后来切换到pusher.com ,这对我来说效果很好,所以我认为它值得你看看。
推荐阅读
- ms-access - 使 Access 数据库字段结构更改传播到 Delphi 应用程序
- java - 将 2 个 sql 表中的数据显示到单个 Jtable
- django - 如何在 Django 中增加会话内部?
- javascript - API 显示 [object, Object] 而不仅仅是事实文本
- python - 范围和 for 循环
- python - TensorFlow“接收到混合的批处理和非批处理张量,或者张量与规格不兼容”
- docker - 未知速记标志:-aq 中的“a”
- python - MS Edge (Chromium) - 无法使用 Selenium WebDriver
- javascript - 带有 WAI-ARIA 的可折叠部分:附加“隐藏”按钮?
- vega-lite - Vega-Lite - 在时间轴上跳过周末(非工作日)