django - 在上下文中使用大型生成器流式传输 Django 模板
问题描述
我想在 Django 模板中呈现大型日志文件。
为此,模板呈现由从磁盘流式传输日志文件的生成器提供的各个行。
模板渲染只是在一段时间后停止,我不确定我哪里出错了。
我的 Django 应用程序正在运行 gunicorn 和 nginx(下面的配置)。
我可以看到设置了相关的响应标头,所以我不知道为什么日志在大约 30-40 秒内停止渲染:
HTTP/1.1 200 OK
Server: nginx/1.17.4
Date: Wed, 12 Feb 2020 12:53:43 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
模板的相关部分:
<div class="log-body">
{% for line in log %}
{{ line }}
{% endfor %}
</div>
中的渲染函数views.py
def render_log(request):
log = read_log_file_gen("some_path.log")
if not log:
log = ["No logs found"]
template = loader.get_template('show_log.html')
context = {
'log': log,
}
return StreamingHttpResponse(template.render(context, request))
def read_log_file_gen(path):
_256KB = 256 * 1024
try:
with open(path) as f:
while True:
lines = f.readlines(_256KB)
if not lines:
break
yield "".join(lines)
except IOError:
return None
该应用程序通过 docker-compose 运行:
version: '3'
services:
web:
build: ./app
command: gunicorn app.wsgi:application --bind 0.0.0.0:8000 -k gevent
volumes:
- static_volume:/usr/src/app/static
- /var/run/docker.sock:/var/run/docker.sock
- /mnt/data:/mnt/data
expose:
- 8000
env_file:
- ./env/.env.prod
nginx:
build: ./nginx
volumes:
- static_volume:/usr/src/app/static
ports:
- 8888:80
depends_on:
- web
volumes:
static_volume:
解决方案
我找到了一种方法来做到这一点,但在此过程中意识到尝试在浏览器中显示大型日志文件是一个坏主意,因为其中一些真的很大。
如果有人尝试这样做(使用稍微少一点的大文件),请注意模板基本上是同步呈现的,因此上述方法实际上不起作用。
相反,您可以加载父模板,并在其中进行 AJAX 调用:
<script>
$(document).ready(function () {
$.ajax({
type: "GET",
url: "{% url 'myapp:logs' log.id %}",
dataType: "text/plain",
success: function (logText) {
$("#logText").replaceWith(logText)
}
});
</script>
然后url 处的函数myapp:logs
可以使用StreamingHttpResponse
:
from django.template import loader
def log(request, log_id):
log_gen = read_log_file_gen(f"{log_id}.log")
template = loader.get_template('mytemplates/log.html')
return StreamingHttpResponse(log_render_gen(template, log_gen))
def log_render_gen(template, log_gen):
for log in log_gen:
yield template.render({'log_line': log})
def read_log_file_gen(path):
_256KB = 256 * 1024
try:
with open(path) as f:
while True:
lines = f.readlines(_256KB)
if not lines:
break
yield "".join(lines)
except IOError:
return None
渲染的异步结果log.html
放在 a<pre>
中,所以我只是按原样渲染日志文本:
{{ log_line }}
推荐阅读
- cmd - GTK+3 应用程序无法在 Windows 上运行
- linux - GCP 计算实例上的部署失败为什么从 Gitlab 推送更改
- javascript - 在 createScript 错误中获取意外的标识符
- r - 提取数据框R列表中列的内容
- postgresql - osm点数据坐标太大
- c# - c#中的另一个变量中的一个变量
- java - vertx executeBlocking 不同的行为
- python - 而在python中没有意义
- java - 当 WebDriverWait 或隐式等待不起作用时如何在 Selenium WebDriver 中等待
- r - 如何根据“已选中”与“未选中”进行重塑