Files
fangke/server/tracker/services/stats.py
T
浅念 cf925e8763 refactor: stats 提取共享 daily_counts
refresh_daily 四指标口径提取为模块级 daily_counts(site, date),
site=None 时聚合全部站点,为 dashboard 今日实时位复用做准备
(Task8 审查结论:防两处口径漂移)。语义不变,既有 stats 测试全绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-15 14:50:09 +08:00

37 lines
1.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from datetime import datetime, time, timedelta
from django.utils import timezone
from tracker.models import DailyStat, Event, VisitSession, Visitor
def daily_counts(site, date) -> dict:
"""四指标共享口径(site=None 聚合全部站点)。所有指标排除爬虫。
日界取 TIME_ZONE(Asia/Shanghai)自然日:make_aware(datetime.combine(date, time.min))。
口径:pv/uv 均从事件表统计(排除 is_bot),uv=distinct visitor,与 pv 同源;
sessions 按会话 started_at 落入当日且访客非爬虫;new_visitors 按 Visitor.first_seen_at 落入当日。
refresh_daily 落库与 dashboard 今日实时位共用此函数,防两处口径漂移(Task8 审查结论)。
"""
day_start = timezone.make_aware(datetime.combine(date, time.min))
day_end = day_start + timedelta(days=1)
ev = Event.objects.filter(is_bot=False,
occurred_at__gte=day_start, occurred_at__lt=day_end)
vs = VisitSession.objects.filter(visitor__is_bot=False,
started_at__gte=day_start, started_at__lt=day_end)
vis = Visitor.objects.filter(is_bot=False,
first_seen_at__gte=day_start, first_seen_at__lt=day_end)
if site is not None:
ev = ev.filter(site=site)
vs = vs.filter(site=site)
vis = vis.filter(site=site)
return {"pv": ev.count(),
"uv": ev.values("visitor").distinct().count(),
"sessions": vs.count(),
"new_visitors": vis.count()}
def refresh_daily(site, date) -> DailyStat:
"""重算某站点某自然日的聚合(幂等,update_or_create)。指标口径见 daily_counts。"""
obj, _ = DailyStat.objects.update_or_create(site=site, date=date,
defaults=daily_counts(site, date))
return obj