如何将Python计时器项目集成到Django并关联HTML页面
将Python计时器集成到Django的分步指南
1. 调整计时器逻辑适配Web环境
原命令行代码依赖input()和本地线程,需改成接收前端参数的形式,同时移除系统通知(后端无法触发客户端系统通知,改用浏览器通知)。在你的Django应用(比如新建timer_app)的views.py中编写处理逻辑:
import time from django.shortcuts import render from django.http import JsonResponse def calculate_end_time(hours, minutes): # 计算总秒数与结束时间 total_seconds = hours * 3600 + minutes * 60 end_timestamp = time.time() + total_seconds return { 'total_seconds': total_seconds, 'end_time': time.ctime(end_timestamp), 'end_timestamp': end_timestamp } def timer_view(request): if request.method == 'POST': # 接收前端传入的时间参数 try: hours = int(request.POST.get('hours', 0)) minutes = int(request.POST.get('minutes', 0)) if hours < 0 or minutes < 0 or (hours == 0 and minutes == 0): return JsonResponse({'error': '无效的时间输入'}, status=400) time_data = calculate_end_time(hours, minutes) return JsonResponse(time_data) except ValueError: return JsonResponse({'error': '请输入有效数字'}, status=400) # GET请求返回计时器页面 return render(request, 'timer/timer.html')
2. 创建前端HTML页面
在timer_app/templates/timer/目录下(需先创建templates和timer子文件夹)新建timer.html,实现输入表单、倒计时显示与通知功能:
<!DOCTYPE html> <html> <head> <title>Django计时器</title> <style> .timer-container { max-width: 400px; margin: 50px auto; padding: 20px; text-align: center; font-family: Arial, sans-serif; } .input-group { margin: 15px 0; } input { padding: 8px; width: 80px; } button { padding: 10px 25px; background-color: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; } #countdown { font-size: 2.5em; margin: 25px 0; color: #333; } #message { color: #f44336; } </style> </head> <body> <div class="timer-container"> <h1>设置计时器</h1> <div class="input-group"> <label>小时: </label> <input type="number" id="hours" min="0" value="0"> </div> <div class="input-group"> <label>分钟: </label> <input type="number" id="minutes" min="0" value="5"> </div> <button onclick="startTimer()">启动计时器</button> <div id="countdown"></div> <div id="message"></div> </div> <script> let countdownInterval; function startTimer() { const hours = parseInt(document.getElementById('hours').value); const minutes = parseInt(document.getElementById('minutes').value); // 向后端发送请求计算结束时间 fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRFToken': getCookie('csrftoken') }, body: `hours=${hours}&minutes=${minutes}` }) .then(response => response.json()) .then(data => { if (data.error) { document.getElementById('message').textContent = data.error; return; } // 初始化倒计时 let remainingSeconds = data.total_seconds; updateCountdown(remainingSeconds); // 每秒更新倒计时状态 countdownInterval = setInterval(() => { remainingSeconds--; if (remainingSeconds <= 0) { clearInterval(countdownInterval); document.getElementById('countdown').textContent = "时间到!"; showNotification(); } else { updateCountdown(remainingSeconds); } }, 1000); }) .catch(error => { document.getElementById('message').textContent = '启动计时器失败'; console.error(error); }); } function updateCountdown(seconds) { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; document.getElementById('countdown').textContent = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; } function showNotification() { if (!("Notification" in window)) { alert("当前浏览器不支持桌面通知"); return; } if (Notification.permission === "granted") { new Notification("休息时间到啦!", { body: `当前时间: ${new Date().toLocaleString()}`, }); } else if (Notification.permission !== "denied") { Notification.requestPermission().then(permission => { if (permission === "granted") { showNotification(); } }); } } // 获取Django CSRF令牌的辅助函数 function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } </script> </body> </html>
3. 配置URL路由
- 在项目根目录的
urls.py中添加应用路由:
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('timer/', include('timer_app.urls')), ]
- 在
timer_app目录下新建urls.py:
from django.urls import path from . import views urlpatterns = [ path('', views.timer_view, name='timer'), ]
4. 关键说明
- 为何不用后端线程?:Django是请求-响应模型,后端线程会在请求结束后被销毁,无法持续运行倒计时逻辑。前端用JavaScript倒计时更符合Web应用交互模式,同时减轻后端压力。
- CSRF令牌:Django默认开启CSRF保护,前端POST请求必须携带令牌,代码中已通过
getCookie函数实现获取。 - 通知功能:改用浏览器通知,因为后端服务器无法直接触发客户端系统通知,浏览器通知需用户提前授权。
运行测试
启动Django开发服务器:
python manage.py runserver
访问http://localhost:8000/timer/,设置时间后点击启动即可看到倒计时,时间到会触发浏览器通知。
内容的提问来源于stack exchange,提问作者user17067764
相关产品推荐
相关产品推荐

