Django初学者求助:关联模型查询应用使用次数与累计节省时长
嘿,作为Django初学者,你的需求我完全get到了——要统计每个自动化应用的使用次数,还有累计帮大家节省的总时长对吧?我来帮你用Django ORM搞定这个,比写原生SQL更顺手,还贴合框架的最佳实践~
先纠正一个小细节
你写的SQL里用Automation_Usage.used_app = Automation_Apps.app_name其实不太准确:used_app是外键字段,它关联的是Automation_Apps的主键(默认是id),不是app_name。不过没关系,用Django ORM的话,这些关联会自动处理,不用我们手动写连接条件。
第一步:优化模型(可选但推荐)
为了让查询代码更易读,我建议给Automation_Usage的外键添加related_name,这样可以直接用友好的名称关联到使用记录:
class Automation_Usage(models.Model): # 添加related_name='usages',方便后续查询 used_app = models.ForeignKey(Automation_Apps, on_delete=models.CASCADE, related_name='usages') used_by_user = models.ForeignKey(User, on_delete=models.CASCADE) used_on_date = models.DateTimeField(auto_now_add=True)
第二步:编写统计查询
用Django的annotate方法可以轻松实现分组统计,同时计算每个应用的使用次数和累计节省时长:
from django.db.models import Count, Sum # 获取每个应用的完整统计数据 app_statistics = Automation_Apps.objects.annotate( # 统计该应用被使用的次数 usage_count=Count('usages'), # 累计节省时长 = 每次使用节省时长的总和(ORM会自动关联求和) total_time_saved=Sum('usages__time_saver_min') ).values( 'app_name', 'app_description', 'time_saver_min', 'usage_count', 'total_time_saved' )
代码解释:
annotate():给每个Automation_Apps对象新增两个统计字段:usage_count(使用次数)和total_time_saved(累计节省时长)values():指定我们需要返回的字段,最终结果是一个字典列表,方便在视图和模板中处理
如果不想修改模型,用Django默认的反向关联名称也可以,把Count('usages')改成Count('automation_usage_set'),Sum('usages__time_saver_min')改成Sum('automation_usage_set__time_saver_min')就行,不过还是推荐加related_name让代码更清晰。
第三步:在视图和模板中使用
视图函数示例:
from django.shortcuts import render from .models import Automation_Apps from django.db.models import Count, Sum def app_stats_view(request): # 获取统计数据 app_stats = Automation_Apps.objects.annotate( usage_count=Count('usages'), total_time_saved=Sum('usages__time_saver_min') ) # 传递数据到模板 return render(request, 'app_stats.html', {'app_stats': app_stats})
模板(app_stats.html)示例:
<!DOCTYPE html> <html> <head> <title>自动化应用统计</title> </head> <body> <h1>自动化应用使用统计</h1> <table border="1"> <tr> <th>应用名称</th> <th>应用描述</th> <th>单次节省时长(分钟)</th> <th>使用次数</th> <th>累计节省时长(分钟)</th> </tr> {% for stat in app_stats %} <tr> <td>{{ stat.app_name }}</td> <td>{{ stat.app_description|default:"无描述" }}</td> <td>{{ stat.time_saver_min }}</td> <td>{{ stat.usage_count }}</td> <!-- 处理未被使用的应用,默认显示0 --> <td>{{ stat.total_time_saved|default:0 }}</td> </tr> {% endfor %} </table> </body> </html>
补充说明
如果某个应用还没有被使用过,usage_count会返回0,total_time_saved会返回None,所以模板里用|default:0来处理空值,避免显示异常。
用Django ORM做统计的好处是:不用手动拼接SQL,避免SQL注入风险,同时代码更易维护,符合Django的设计理念。
内容的提问来源于stack exchange,提问作者Oliver Demus

