You need to enable JavaScript to run this app. Django/Python 如何实现无需刷新的实时下载进度计数显示
优惠活动
大模型
产品
解决方案
定价
更多

Django/Python 如何实现无需刷新的实时下载进度计数显示

核心问题说明

你现在的代码从根上就不满足实时更新的逻辑,有两个绕不开的问题:

  • views.py里的while循环逻辑完全失效:你在循环体内算出进度值后立刻执行return render(...),第一次循环还没走完就直接把响应返回给浏览器、后端函数就退出了,根本不会执行第二次循环
  • 所有后端Web框架(包括Django)的基础运行逻辑都是「浏览器发1次请求,后端返回1次响应,连接随即断开」,你没法在一个后端的循环里,持续把不同的进度值推送到已经发给用户的页面上,这是Web的基础通信模式决定的,不是代码写得不对。
适合初学者的最简实现方案

不用碰复杂的实时通信技术,用「后端拆分接口+前端定时轮询」的方式就能实现无手动刷新的进度更新,改动量小、逻辑好懂:

第一步:重构后端视图逻辑

不要把触发下载、查询进度、返回页面的逻辑全塞在一个视图函数里,拆成两个独立接口:

  1. 触发下载的接口:用户点开始下载时调用,负责和qbittorrent客户端通信启动下载,直接返回进度展示页面,不在这个接口里循环等进度跑完
  2. 进度查询接口:专门供前端定时调用,每次被访问时实时计算当前下载进度,返回JSON格式的数值,不用返回完整的HTML页面

对应views.py的修改示例:

# 入门阶段可以先用全局变量临时存任务标识,快速跑通逻辑
qb_client = Client("http://www.on-demandlogistics.com:8080/")
qb_client.login("admin", "adminadmin")
# 存当前下载任务的torrent hash
current_task_hash = "cca0bf46ce95c802e6a8f0e1f353978d12da6997"

def start_download_view(request):
    qb_client.download_from_link(torrentLink)
    # 直接返回进度页面,不做循环等待
    return render(request, "movies/dbsearch.html", {
        "movie_name": "Downloading " + movie_name[0].title() + " now!"
    })

def query_progress_view(request):
    # 每次被调用时实时查最新进度
    torrent_info = qb_client.get_torrent(current_task_hash)
    progress = int(
        float(torrent_info['total_downloaded']) 
        / float(torrent_info['total_size']) 
        * 100
    )
    # 判断是否下载完成
    is_finished = progress >= 100
    # 返回JSON格式的进度数据
    return JsonResponse({
        "progress": progress,
        "is_finished": is_finished
    })

记得在项目的urls.py里注册这两个新接口的路由:

from django.urls import path
from . import views

urlpatterns = [
    path('start-download/', views.start_download_view),
    path('api/query-progress/', views.query_progress_view),
]

第二步:修改前端页面,加定时自动更新逻辑

在原来的页面基础上,用最基础的原生JS写定时轮询逻辑,不需要引入任何前端框架:

<!DOCTYPE html>
<html>
<head>
<title>dbSearch</title>
</head>
<body>

<h1>{{movie_name}}</h1>
<!-- 给进度元素加id,方便JS定位更新 -->
<h2 id="progress-text">0%</h2>
<!-- 简单的可视化进度条 -->
<div style="width: 80%; height: 20px; background: #f0f0f0; margin: 10px 0;">
  <div id="progress-bar" style="height: 100%; width: 0%; background: #2196f3;"></div>
</div>

<script>
// 每1000毫秒(1秒)请求一次后端的进度接口
const refreshTimer = setInterval(async () => {
  // 调用后端的进度查询接口
  const response = await fetch('/api/query-progress/');
  const progressData = await response.json();
  // 把拿到的进度值更新到页面上
  document.getElementById('progress-text').innerText = progressData.progress + '%';
  document.getElementById('progress-bar').style.width = progressData.progress + '%';
  // 进度到100%时停止定时查询,改成显示完成提示
  if (progressData.is_finished) {
    clearInterval(refreshTimer);
    document.getElementById('progress-text').innerText = 'Download Complete!';
  }
}, 1000)
</script>

</body>
</html>
入门阶段需要注意的细节
  • 示例里用全局变量存任务信息只是为了快速跑通逻辑,如果后续要支持多用户同时使用,需要给每个用户的下载任务绑定唯一标识,存在用户会话或者数据库里,否则多用户访问时进度会互相串
  • 这种定时轮询的方式逻辑简单、好调试,对于下载进度这种不需要毫秒级实时的场景完全够用,不用一开始就强行上WebSocket、SSE等复杂的实时通信方案,等熟悉了Web通信逻辑再优化也不迟
  • 你原来的代码里两次调用qb.get_torrent()查同一个任务的信息,可以像示例里那样把查询结果存在临时变量里复用,减少重复的API请求,提升效率

内容的提问来源于stack exchange,提问作者littlejiver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.04 22:54:05