如何在Django中跨多日追踪用户学习时长并按周重置?
解决方案
1. 调整Django数据模型
原有的totallearningtime字段仅能存储累计总时长,无法按天拆分记录。需要新增每日学习时长模型,用来追踪用户每天的学习时间:
from django.db import models from django.contrib.auth.models import User from django.utils import timezone class DailyLearningTime(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='daily_learning_times') date = models.DateField(default=timezone.now) daily_duration = models.DecimalField(default=0, decimal_places=2, max_digits=10) # 当天学习时长,单位可根据需求调整为分钟/小时 class Meta: unique_together = ('user', 'date') # 确保用户每天仅存一条记录
原有的totallearningtime字段可保留用于累计总时长统计,也可通过DailyLearningTime的记录总和计算,按需选择。
2. 实现每日时长更新逻辑
当用户产生学习行为时,调用以下逻辑更新对应日期的学习时长:
def update_daily_learning_time(user, add_duration): today = timezone.now().date() # 获取或创建当天的学习记录 daily_record, created = DailyLearningTime.objects.get_or_create(user=user, date=today) daily_record.daily_duration += add_duration daily_record.save() # 可选:同步更新用户总学习时长 user.profile.totallearningtime += add_duration # 假设总时长存储在User关联的Profile模型中 user.profile.save()
3. 后端接口:获取当前周学习数据
编写视图接口,返回当前用户本周(周一至周日)的每日学习时长,格式适配Chart.js:
from django.http import JsonResponse from django.utils import timezone from datetime import timedelta def weekly_learning_data(request): if not request.user.is_authenticated: return JsonResponse({'error': '未登录'}, status=401) user = request.user # 计算本周一的日期(weekday()返回0=周一,6=周日) today = timezone.now().date() start_of_week = today - timedelta(days=today.weekday()) end_of_week = start_of_week + timedelta(days=6) # 查询本周所有学习记录 weekly_records = DailyLearningTime.objects.filter( user=user, date__gte=start_of_week, date__lte=end_of_week ).values('date', 'daily_duration') # 构建周一到周日的完整数据,缺失日期填充0 week_days = [start_of_week + timedelta(days=i) for i in range(7)] day_labels = ['Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'] daily_data = [] for day in week_days: record = next((r for r in weekly_records if r['date'] == day), None) daily_data.append(float(record['daily_duration']) if record else 0) return JsonResponse({ 'labels': day_labels, 'data': daily_data, 'total_weekly_time': sum(daily_data) # 可选:返回本周总时长 })
在urls.py中配置接口路由:
from django.urls import path from .views import weekly_learning_data urlpatterns = [ # ... 其他路由 path('api/weekly-learning-data/', weekly_learning_data, name='weekly_learning_data'), ]
4. 修改前端Chart.js代码,动态加载数据
替换静态占位数据,通过AJAX请求后端接口获取本周数据:
<canvas id="myChart"></canvas> <script> const ctx = document.getElementById("myChart"); // 从后端获取每周学习数据 fetch('/api/weekly-learning-data/') .then(response => response.json()) .then(data => { new Chart(ctx, { type: "line", data: { labels: data.labels, datasets: [ { label: "Learning Time", data: data.data, fill: false, cubicInterpolationMode: "monotone", tension: 0.4, borderColor: '#ff6384' // 自定义线条颜色 }, ], }, options: { responsive: true, maintainAspectRatio: true, plugins: { title: { display: true, text: `Total Time: ${Math.floor(data.total_weekly_time/60)}h ${Math.round(data.total_weekly_time%60)}m` // 格式化总时长显示 }, }, interaction: { intersect: false, }, scales: { x: { display: true, title: { display: true, text: 'Week Days' }, }, y: { display: true, title: { display: true, text: "Minutes", // 与后端数据单位保持一致,可改为Hours }, suggestedMin: 0, suggestedMax: 200, }, }, }, }); }) .catch(error => console.error('获取数据失败:', error)); </script>
关键说明
- 每周重置逻辑:无需手动重置数据,后端接口每次仅查询当前自然周的记录,自动实现“每周从零开始统计”的效果,同时保留历史周数据。
- 时区处理:确保Django
settings.py中TIME_ZONE配置正确,避免日期计算偏差。 - 单位统一:注意
daily_duration的单位(分钟/小时),前端图表Y轴标签需与之对应。
内容的提问来源于stack exchange,提问作者Jahan Manu
相关产品推荐
相关产品推荐

